From 32998838c8550f447f97cb9d5956f16084df3664 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 25 Aug 2017 16:26:37 +0200 Subject: [PATCH 001/247] add test IF GT8 --- tests/functional/runtime/ifgt8.bas | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 tests/functional/runtime/ifgt8.bas diff --git a/tests/functional/runtime/ifgt8.bas b/tests/functional/runtime/ifgt8.bas new file mode 100644 index 000000000..cc32aad43 --- /dev/null +++ b/tests/functional/runtime/ifgt8.bas @@ -0,0 +1,21 @@ + +DIM i, j, k as Byte + +i = 127 +DO + i = i + 1 + j = 127 + DO + j = j + 1 + IF i > j THEN + let k = i > j + if not k THEN + PRINT i; " !> "; j; " "; FLASH 1; INK 2; " ERROR " + STOP + END IF + END IF + LOOP UNTIL j = 127 +LOOP UNTIL i = 127 + +PRINT PAPER 4; INK 7; " SUCCESS "; PAPER 8; TAB 31 + From 935f8166d960b896e7b9f12758d3d4df02756fb0 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 30 Aug 2017 00:42:12 +0200 Subject: [PATCH 002/247] change from GPL to MIT license --- library/radastan.bas | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/radastan.bas b/library/radastan.bas index 4863e179f..54ce5ec77 100644 --- a/library/radastan.bas +++ b/library/radastan.bas @@ -1,7 +1,7 @@ ' ---------------------------------------------------------------- -' This file is released under the GPL v3 License +' This file is released under the MIT License ' -' Copyleft (k) 2008 +' Copyleft (k) 2017 ' by Jose Rodriguez-Rosa (a.k.a. Boriel) ' ' Radastan mode library for ZX UNO and compatible machines From eb755b0b0bf2252aa9d42bcda7c563230e3e5ff4 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 26 Aug 2017 00:09:30 +0200 Subject: [PATCH 003/247] implement RadastanDraw --- library/radastan.bas | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/library/radastan.bas b/library/radastan.bas index 54ce5ec77..ed947f1d1 100644 --- a/library/radastan.bas +++ b/library/radastan.bas @@ -93,9 +93,20 @@ rplotfin: end sub -sub RadastanDraw(ByVal x1 as Byte, ByVal y1 as Byte, Byval colorIdx as Ubyte) - DIM dx, dy, dx2, dy2, x, y, x0, y0, sx, sy as Byte - DIM p, iE, iNE as Byte +' ---------------------------------------------------------------- +' function RadastanDraw +' +' Draws a line from the last plotted position to the given coords. +' +' Parameters: +' x: coord x (horizontal) of pixel to plot +' y: coord y (vertical) of pixel to plot +' color: color palette (0..15) +' ---------------------------------------------------------------- +SUB RadastanDraw(ByVal x1 as Byte, ByVal y1 as Byte, Byval colorIdx as Ubyte) + DIM sx, sy as Byte + DIM x, y, x0, y0 as Byte + DIM p, dx, dy, iE, iNE as Integer LET x0 = PEEK 5C7Dh LET y0 = PEEK 5C7Eh @@ -146,17 +157,17 @@ sub RadastanDraw(ByVal x1 as Byte, ByVal y1 as Byte, Byval colorIdx as Ubyte) RadastanPlot(x, y, colorIdx) END WHILE END IF -end sub +END SUB -sub RadastanPalette(ByVal colorIndex as Ubyte, ByVal rgb as UByte) ' color=0-15, rgb = binary GGGRRRBB +SUB RadastanPalette(ByVal colorIndex as Ubyte, ByVal rgb as UByte) ' color=0-15, rgb = binary GGGRRRBB OUT 48955, 64: OUT 65339, 1 OUT 48955, colorIndex: OUT 65339, rgb -end sub +END SUB -sub fastcall RadastanCls(color as ubyte) - asm +SUB fastcall RadastanCls(color as ubyte) + ASM and 0xF ld b, a rla @@ -169,8 +180,10 @@ sub fastcall RadastanCls(color as ubyte) ld bc, 6143 ld (hl), a ldir - end asm -end Sub + ld hl, 0 + ld (5C7Dh), hl ; COORDS + END ASM +END SUB #endif From 8d3cdbd9b5c28a205f765ad8fcffc8ac3cf2b87d Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 26 Aug 2017 00:59:12 +0200 Subject: [PATCH 004/247] implement RadastanCircle --- library/radastan.bas | 109 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 103 insertions(+), 6 deletions(-) diff --git a/library/radastan.bas b/library/radastan.bas index ed947f1d1..71a1d71af 100644 --- a/library/radastan.bas +++ b/library/radastan.bas @@ -30,7 +30,7 @@ end sub ' ---------------------------------------------------------------- -' function RadastanPlot +' Sub RadastanPlot ' ' Parameters: ' x: coord x (horizontal) of pixel to plot @@ -93,14 +93,57 @@ rplotfin: end sub +Function fastcall RadastanPoint(ByVal x as ubyte, ByVal y as ubyte) as Byte + ASM + PROC + LOCAL next2 + pop hl ; ret addr + pop de ; D = y + ld e, a ; E = x + ex (sp), hl ; callee, h = color + ld a, 127 + cp e + ld a, -1 + ret c ; Out of screen + ld a, 95 + cp d + ld a, -1 + ret c ; Out of screen + ld a, d + rrca + rrca + and 192 + or e + ld l, a + ld a, d + rrca + rrca + and 63 + or 64 + ld h, a + ld a, (hl) + rr e + jr c, next2 + rla + rla + rla + rla +next2: + and 0xF + ENDP + END ASM +End Function + + + ' ---------------------------------------------------------------- -' function RadastanDraw +' Sub RadastanDraw ' ' Draws a line from the last plotted position to the given coords. ' ' Parameters: -' x: coord x (horizontal) of pixel to plot -' y: coord y (vertical) of pixel to plot +' x: coord x (horizontal) of last pixel to plot +' y: coord y (vertical) of last pixel to plot ' color: color palette (0..15) ' ---------------------------------------------------------------- SUB RadastanDraw(ByVal x1 as Byte, ByVal y1 as Byte, Byval colorIdx as Ubyte) @@ -160,13 +203,67 @@ SUB RadastanDraw(ByVal x1 as Byte, ByVal y1 as Byte, Byval colorIdx as Ubyte) END SUB -SUB RadastanPalette(ByVal colorIndex as Ubyte, ByVal rgb as UByte) ' color=0-15, rgb = binary GGGRRRBB +' ---------------------------------------------------------------- +' Sub RadastanCircle +' +' Draws a Circle of radius r with center (x, y) +' +' Parameters: +' x: coord x (horizontal) of circle center +' y: coord y (vertical) of circle center +' r: radius (in pixels) +' color: color palette (0..15) +' ---------------------------------------------------------------- +SUB RadastanCircle(ByVal x0 as Byte, ByVal y0 as Byte, ByVal r as Byte, ByVal colorIdx as UByte) + DIM x, y, dx, dy, err as Byte + + x = r - 1 + y = 0 + dx = 1 + dy = 1 + err = dx - (r << 1) + + WHILE x >= y + RadastanPlot(x0 + x, y0 + y, colorIdx) + RadastanPlot(x0 + y, y0 + x, colorIdx) + RadastanPlot(x0 - y, y0 + x, colorIdx) + RadastanPlot(x0 - x, y0 + y, colorIdx) + RadastanPlot(x0 - x, y0 - y, colorIdx) + RadastanPlot(x0 - y, y0 - x, colorIdx) + RadastanPlot(x0 + y, y0 - x, colorIdx) + RadastanPlot(x0 + x, y0 - y, colorIdx) + + IF err <= 0 THEN + y = y + 1 + err = err + dy + dy = dy + 2 + END IF + + IF err > 0 THEN + x = x - 1 + dx = dx + 2 + err = err + (-r << 1) + dx + END IF + END WHILE +END SUB + + +' ---------------------------------------------------------------- +' sub RadastanPalette +' +' Defines a palette entry +' +' Parameters: +' colorIndex: Palete index entry (0..15) +' rgb: Color value rgb = binary GGGRRRBB +' ---------------------------------------------------------------- +SUB RadastanPalette(ByVal colorIndex as Ubyte, ByVal rgb as UByte) ' OUT 48955, 64: OUT 65339, 1 OUT 48955, colorIndex: OUT 65339, rgb END SUB -SUB fastcall RadastanCls(color as ubyte) +SUB fastcall RadastanCls(ByVal color as UByte) ASM and 0xF ld b, a From 1cb4c2ad270c7100188eb7b94bf1e9a552916fe5 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 29 Aug 2017 12:56:15 +0200 Subject: [PATCH 005/247] implement RadastanPoint --- library/radastan.bas | 53 +++++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/library/radastan.bas b/library/radastan.bas index 71a1d71af..ecb47640e 100644 --- a/library/radastan.bas +++ b/library/radastan.bas @@ -14,15 +14,11 @@ REM Avoid recursive / multiple inclusion #define __LIBRARY_RADASTAN__ ' ---------------------------------------------------------------- -' function NAME +' function RadastanMode ' ' Parameters: -' x -' y -' -' Returns: -' (When nothing to return, use SUB instead) -' ---------------------------------------------------------------- +' enable: 0 => disable (normal mode), otherwise radastan mode +'' ---------------------------------------------------------------- sub RadastanMode(enable as Ubyte) OUT 64571, 64 OUT 64827, 3 * SGN(enable) @@ -93,41 +89,54 @@ rplotfin: end sub +' ---------------------------------------------------------------- +' Sub RadastanPoint +' +' Parameters: +' x: coord x (horizontal) of pixel to examine +' y: coord y (vertical) of pixel to examine +' +' Returns: +' color: color palette (0..15) or -1 if out of screen +' ---------------------------------------------------------------- Function fastcall RadastanPoint(ByVal x as ubyte, ByVal y as ubyte) as Byte ASM PROC LOCAL next2 pop hl ; ret addr - pop de ; D = y + ex (sp), hl ; callee => h = y ld e, a ; E = x - ex (sp), hl ; callee, h = color ld a, 127 cp e ld a, -1 ret c ; Out of screen ld a, 95 - cp d + cp h ld a, -1 ret c ; Out of screen - ld a, d + xor a + rr e + adc a, a + ld c, a ; c = 0 if even, 1 if odd + ld a, h rrca rrca and 192 or e ld l, a - ld a, d + ld a, h rrca rrca and 63 or 64 ld h, a ld a, (hl) - rr e + rr c jr c, next2 - rla - rla - rla - rla + rra + rra + rra + rra next2: and 0xF ENDP @@ -263,7 +272,15 @@ SUB RadastanPalette(ByVal colorIndex as Ubyte, ByVal rgb as UByte) ' END SUB -SUB fastcall RadastanCls(ByVal color as UByte) +' ---------------------------------------------------------------- +' Sub RadastanCls +' +' Clears the screen with the given color +' +' Parameters: +' col: Color index (0..15) +' ---------------------------------------------------------------- +SUB fastcall RadastanCls(ByVal col as UByte) ASM and 0xF ld b, a From ca393a39e8dc27b838cd12ee37ca30839cbc2675 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 29 Aug 2017 21:50:13 +0200 Subject: [PATCH 006/247] implement RadastanFill --- library/radastan.bas | 56 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/library/radastan.bas b/library/radastan.bas index ecb47640e..3c450ff2e 100644 --- a/library/radastan.bas +++ b/library/radastan.bas @@ -300,4 +300,60 @@ SUB fastcall RadastanCls(ByVal col as UByte) END SUB +' ---------------------------------------------------------------- +' sub RadastanFill +' +' Fills the figure with the given color starting from the given +' coordinate. +' +' Parameters: +' x: coord x (horizontal) of starting point +' y: coord y (vertical) of starting point +' color: fill color, palette (0..15) +' ---------------------------------------------------------------- +SUB RadastanFill(Byval x as UByte, ByVal y as UByte, ByVal col as Ubyte) + Const L as Uinteger = 1023 + Const L2 as Uinteger = L * 2 + 1 + DIM buff(L, 1) as UByte + DIM i, j, paddr as Uinteger + DIM c as Byte + + paddr = @buff(0, 0) + +#define P(x, y) \ + POKE paddr + j, x \ + j = j + 1 \ + POKE paddr + j, y \ + j = (j + 1) bAND L2 + + c = RadastanPoint(x, y) + IF c = -1 THEN ' -1 => Out of Screen + RETURN + END IF + + i = 0 + j = 0 + P(x, y) + + WHILE i <> j + x = PEEK(paddr + i) + i = i + 1 + y = PEEK(paddr + i) + i = (i + 1) bAND L2 + + IF c <> RadastanPoint(x, y) THEN + CONTINUE WHILE + END IF + + RadastanPlot(x, y, col) + P(x + 1, y) + P(x - 1, y) + P(x, y + 1) + P(x, y - 1) + END WHILE + +#undef P +END SUB + + #endif From fb2202198d2dbe5b1a34c774f4291ff38a9f72eb Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 30 Aug 2017 00:42:30 +0200 Subject: [PATCH 007/247] implement RadastanHLine --- library/radastan.bas | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/library/radastan.bas b/library/radastan.bas index 3c450ff2e..91d95195b 100644 --- a/library/radastan.bas +++ b/library/radastan.bas @@ -144,6 +144,32 @@ next2: End Function +' ---------------------------------------------------------------- +' Sub RadastanHLine +' +' Draws an horizontal line from (x0, y) to (x1, y) +' +' Parameters: +' x0: coord x (horizontal) of first pixel to plot +' y: coord y (vertical) of first pixel to plot +' x1: coord x (horizontal) of the last pixel to plot +' color: color palette (0..15) +' ---------------------------------------------------------------- +Sub RadastanHLine(ByVal x0 as UByte, ByVal y as UByte, ByVal x1 as UByte, ByVal col as UByte) + Dim x as UByte + + if x1 < x0 + x = x1 + x1 = x0 + x0 = x + end if + + FOR x = x0 TO x1 + RadastanPlot(x, y, col) + NEXT x + +End Sub + ' ---------------------------------------------------------------- ' Sub RadastanDraw From 692c1234040b349ebe34304281d405f27942c44b Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 29 Aug 2017 23:39:50 +0200 Subject: [PATCH 008/247] implement RadastanFillCircle --- library/radastan.bas | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/library/radastan.bas b/library/radastan.bas index 91d95195b..52fbbb429 100644 --- a/library/radastan.bas +++ b/library/radastan.bas @@ -283,6 +283,47 @@ SUB RadastanCircle(ByVal x0 as Byte, ByVal y0 as Byte, ByVal r as Byte, ByVal co END SUB +' ---------------------------------------------------------------- +' Sub RadastanFillCircle +' +' Fills a Circle of radius r with center (x, y) +' +' Parameters: +' x: coord x (horizontal) of circle center +' y: coord y (vertical) of circle center +' r: radius (in pixels) +' color: color palette (0..15) +' ---------------------------------------------------------------- +SUB RadastanFillCircle(ByVal x0 as Byte, ByVal y0 as Byte, ByVal r as Byte, ByVal colorIdx as UByte) + DIM x, y, dx, dy, err as Byte + + x = r - 1 + y = 0 + dx = 1 + dy = 1 + err = dx - (r << 1) + + WHILE x >= y + RadastanHLine(x0 - x, y0 + y, x0 + x, colorIdx) + RadastanHLine(x0 - y, y0 + x, x0 + y, colorIdx) + RadastanHLine(x0 - x, y0 - y, x0 + x, colorIdx) + RadastanHLine(x0 - y, y0 - x, x0 + y, colorIdx) + + IF err <= 0 THEN + y = y + 1 + err = err + dy + dy = dy + 2 + END IF + + IF err > 0 THEN + x = x - 1 + dx = dx + 2 + err = err + (-r << 1) + dx + END IF + END WHILE +END SUB + + ' ---------------------------------------------------------------- ' sub RadastanPalette ' From cdf2672de63febbd133a7bd9e1197f29a92d815d Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 30 Aug 2017 23:55:14 +0200 Subject: [PATCH 009/247] implement RadastanSrollUp --- library/radastan.bas | 45 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/library/radastan.bas b/library/radastan.bas index 52fbbb429..fc49472a5 100644 --- a/library/radastan.bas +++ b/library/radastan.bas @@ -423,4 +423,49 @@ SUB RadastanFill(Byval x as UByte, ByVal y as UByte, ByVal col as Ubyte) END SUB +' ---------------------------------------------------------------- +' sub RadastanScrollUp +' +' Scrolls ups the screen the given number of lines (up to 96). +' The new entering lines are filled with color index 0 +' +' Parameters: +' lines: number of lines to scroll up +' ---------------------------------------------------------------- +SUB FASTCALL RadastanScrollUp(ByVal lines As Byte) + ASM + ; scrolls up + cp 97 + ret nc + ccf + ld e, 0 + rra + rr e + rra + rr e + ld d, a ; de = lines * 64 + ld hl, 6144 + sbc hl, de ; hl = 6144 - lines * 64 + push de + + ld b, h + ld c, l ; bc = 6144 - lines * 64 + ex de, hl ; hl = lines * 64 + ld de, (__RADASTAN_SCR_ADDR) + add hl, de ; hl = scr_addr + lines * 64 + ldir + + ; blank last 6 scanlines + xor a + ld (de), a + ld h, d + ld l, e + inc de + pop bc + dec bc + ldir + END ASM +END SUB + + #endif From 58802ef2c821a3124c676b490fe7395b95c8adbe Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 1 Sep 2017 22:57:21 +0200 Subject: [PATCH 010/247] implement RadastanPrintChar --- library/radastan.bas | 154 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/library/radastan.bas b/library/radastan.bas index fc49472a5..059c38fa3 100644 --- a/library/radastan.bas +++ b/library/radastan.bas @@ -363,7 +363,9 @@ SUB fastcall RadastanCls(ByVal col as UByte) ldir ld hl, 0 ld (5C7Dh), hl ; COORDS + ld (__RADASTAN_PRN_POS), hl END ASM + LET a = @RadastanPrintAt END SUB @@ -422,6 +424,158 @@ SUB RadastanFill(Byval x as UByte, ByVal y as UByte, ByVal col as Ubyte) #undef P END SUB +' ---------------------------------------------------------------- +' Sub RadastanPrintAt +' +' Places the printing cursor at the given row, column coordinates +' +' Parameters: +' row: cursor row (0..31) +' col: cursor column (0..15) +' ---------------------------------------------------------------- +SUB FASTCALL RadastanPrintAt(ByVal row as UByte, ByVal col as Ubyte) + ASM + ; A register contains row + pop hl + ex (sp), hl ; h = col + ld l, h + ld h, a + ld (__RADASTAN_PRN_POS), hl + ret + END ASM +END SUB + + +SUB FASTCALL RadastanSetFont(ByVal fontaddress as Uinteger) + ASM + ld (__RADASTAN_FONT), hl + END ASM +END SUB + + +SUB FASTCALL RadastanSetScreenAddr(ByVal fontaddress as Uinteger) + ASM + ld (__RADASTAN_SCRN_ADDR), hl + END ASM +END SUB + + +SUB FASTCALL RadastanPrintChar(ByVal char as UByte) + ASM + PROC + LOCAL font, no_inter + + ; FASTCALL => a reg contains char + push ix + ld ix, 0 + add ix, sp + sub ' ' + ld b, a + add a, a + add a, b ; multiplico por 3 + ld h, 0 + ld l, a + add hl, hl + add hl, hl ; multiplico por 12 + +__RADASTAN_FONT equ $+1 + ld bc, font + add hl, bc + ld a, r + ex af, af' + di + ld sp, hl + + ld a, (__RADASTAN_PRN_POS + 1) + ld l, a + add a, a + add a, l + add a, a + ld l, 0 + rra + rr l + rra + rr l + ld h, a ; hl = a * 64 => row * 6 * 64 + ld a, (__RADASTAN_PRN_POS) ; col + add a, a + add a, l + ld l, a + +__RADASTAN_SCR_ADDR equ $+1 ; Write here screen offset + ld bc, 16384 ; Screen offset + add hl, bc + ld bc, 63 + + pop de + ld (hl), e ; pinto primera fila + inc hl + ld (hl), d + add hl, bc + + pop de + ld (hl), e ; pinto segunda fila + inc hl + ld (hl), d + add hl, bc + + pop de + ld (hl), e ; pinto tercera fila + inc hl + ld (hl), d + add hl, bc + + pop de + ld (hl), e ; pinto cuarta fila + inc hl + ld (hl), d + add hl, bc + + pop de + ld (hl), e ; pinto quinta fila + inc hl + ld (hl), d + add hl, bc + + pop de + ld (hl), e ; pinto sexta fila + inc hl + ld (hl), d + + ld sp, ix + ex af, af' + jp po, no_inter + ei +no_inter: + pop ix + + ld hl, __RADASTAN_PRN_POS + inc (hl) + ld a, 31 + cp (hl) + ret nc + xor a + ld (hl), a + inc hl + inc (hl) + ld a, 15 + cp (hl) + ret nc + ld (hl), a + ld a, 6 + jp _RadastanScrollUp + +__RADASTAN_PRN_POS: + dw 0 + +font: + incbin "haplofnt.bin" + + ENDP + END ASM + dummy = @RadastanScrollUp +END SUB + ' ---------------------------------------------------------------- ' sub RadastanScrollUp From 47d304b1b41a6508a4a354a418f31006634a05ab Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 3 Sep 2017 20:36:24 +0200 Subject: [PATCH 011/247] make all routines to accept screen ptr By setting the variable RadastanScrAddr it's possible to change the screen address. --- library/radastan.bas | 143 +++++++++++++++++++++++++++++-------------- 1 file changed, 97 insertions(+), 46 deletions(-) diff --git a/library/radastan.bas b/library/radastan.bas index 059c38fa3..fab39c4a4 100644 --- a/library/radastan.bas +++ b/library/radastan.bas @@ -13,6 +13,17 @@ REM Avoid recursive / multiple inclusion #define __LIBRARY_RADASTAN__ + +#define RADASTAN_FONT RadastanHaploFont + +DIM RadastanScrAddr as UInteger = 16384 +DIM RadastanColRow as UInteger = 0 +DIM RadastanFontAddr as UInteger = @RADASTAN_FONT + + +REM Dummy lines (leave them for now) +dummy = RadastanScrAddr + RadastanColRow + RadastanFontAddr + ' ---------------------------------------------------------------- ' function RadastanMode ' @@ -55,35 +66,36 @@ COORDS EQU 5C7Dh adc a, a xor 1 ld h, a + ld c, 0 ld a, d ;' recuperamos el valor vertical - rrca - rrca ;' rotamos para dejar su valor en multiplos de 64 (linea, de dos en dos pixels) - and 192 ;' borramos el resto de bits por si las moscas - or e ;' sumamos el valor horizontal - ld e, a ;' e preparado - ld a, d ;' cargamos el valor vertical - rrca - rrca ;' rotamos para quedarnos con los bits altos - and 63 ;' borramos el resto de bits - or 64 ;' nos posicionamos a partir de 16384 (16384=64+0 en dos bytes) - ld d, a ;' d preparado, ya tenemos la posicion en pantalla - ld a,(de) - rr h + rra + rr c + rra + rr c + ld b, a + ld a, e + add a, c + ld c, a + ex de, hl + ld hl, (_RadastanScrAddr) + add hl, bc + ld a,(hl) + rr d jr c, rplotnext2 and 240 - or l + or e jr rplotfin rplotnext2: and 15 - rl l - rl l - rl l - rl l - or l + rl e + rl e + rl e + rl e + or e rplotfin: - ld (de), a + ld (hl), a ENDP end asm end sub @@ -128,8 +140,9 @@ Function fastcall RadastanPoint(ByVal x as ubyte, ByVal y as ubyte) as Byte rrca rrca and 63 - or 64 ld h, a + ld de, (_RadastanScrAddr) + add hl, de ld a, (hl) rr c jr c, next2 @@ -356,16 +369,17 @@ SUB fastcall RadastanCls(ByVal col as UByte) rla rla or b - ld hl, 16384 - ld de, 16385 + ld hl, (_RadastanScrAddr) + ld d, h + ld e, l + inc de ld bc, 6143 ld (hl), a ldir ld hl, 0 ld (5C7Dh), hl ; COORDS - ld (__RADASTAN_PRN_POS), hl + ld (_RadastanColRow), hl END ASM - LET a = @RadastanPrintAt END SUB @@ -424,6 +438,7 @@ SUB RadastanFill(Byval x as UByte, ByVal y as UByte, ByVal col as Ubyte) #undef P END SUB + ' ---------------------------------------------------------------- ' Sub RadastanPrintAt ' @@ -440,30 +455,43 @@ SUB FASTCALL RadastanPrintAt(ByVal row as UByte, ByVal col as Ubyte) ex (sp), hl ; h = col ld l, h ld h, a - ld (__RADASTAN_PRN_POS), hl + ld (_RadastanColRow), hl ret END ASM END SUB +' ---------------------------------------------------------------- +' sub RadastanSetFont +' +' Sets the font to be used for printing by passing the address to +' it. +' +' Parameters: +' fontaddress: memory address of the font memory area +' ---------------------------------------------------------------- SUB FASTCALL RadastanSetFont(ByVal fontaddress as Uinteger) - ASM - ld (__RADASTAN_FONT), hl - END ASM + RadastanFontAddr = fontaddress END SUB -SUB FASTCALL RadastanSetScreenAddr(ByVal fontaddress as Uinteger) - ASM - ld (__RADASTAN_SCRN_ADDR), hl - END ASM +' ---------------------------------------------------------------- +' sub RadastanSetScreenAddr +' +' Sets the start of the screen for these routines +' +' Parameters: +' scraddr: memory address of the beginning of screen area +' ---------------------------------------------------------------- +SUB FASTCALL RadastanSetScreenAddr(ByVal scraddr as Uinteger) + RadastanScrAddr = scraddr END SUB SUB FASTCALL RadastanPrintChar(ByVal char as UByte) ASM PROC - LOCAL font, no_inter + LOCAL no_inter ; FASTCALL => a reg contains char push ix @@ -478,15 +506,14 @@ SUB FASTCALL RadastanPrintChar(ByVal char as UByte) add hl, hl add hl, hl ; multiplico por 12 -__RADASTAN_FONT equ $+1 - ld bc, font + ld bc, (_RadastanFontAddr) add hl, bc ld a, r ex af, af' di ld sp, hl - ld a, (__RADASTAN_PRN_POS + 1) + ld a, (_RadastanColRow + 1) ld l, a add a, a add a, l @@ -497,13 +524,12 @@ __RADASTAN_FONT equ $+1 rra rr l ld h, a ; hl = a * 64 => row * 6 * 64 - ld a, (__RADASTAN_PRN_POS) ; col + ld a, (_RadastanColRow) ; col add a, a add a, l ld l, a -__RADASTAN_SCR_ADDR equ $+1 ; Write here screen offset - ld bc, 16384 ; Screen offset + ld bc, (_RadastanScrAddr) ; Screen offset add hl, bc ld bc, 63 @@ -549,9 +575,10 @@ __RADASTAN_SCR_ADDR equ $+1 ; Write here screen offset no_inter: pop ix - ld hl, __RADASTAN_PRN_POS - inc (hl) ld a, 31 +__RADASTAN_NEXT_PRN_POS: + ld hl, _RadastanColRow + inc (hl) cp (hl) ret nc xor a @@ -567,13 +594,37 @@ no_inter: __RADASTAN_PRN_POS: dw 0 + ENDP + END ASM + DIM dummy as Uinteger + dummy = @RadastanScrollUp +END SUB -font: + +' ---------------------------------------------------------------- +' Sub RadastanHaploFont +' +' Actually not a Sub (do not call!). This just defines the font +' in a function. Use @RadastanHaploFont +' ---------------------------------------------------------------- +SUB FASTCALL RadastanHaploFont + ASM incbin "haplofnt.bin" + END ASM +END SUB - ENDP + +' ---------------------------------------------------------------- +' sub RadastaPrintNL +' +' Prints a New Line (update cursor position to the beginning of +' the new line. +' ---------------------------------------------------------------- +SUB FASTCALL RadastanPrintNL() + ASM + xor a + jp __RADASTAN_MOVE_CURSOR END ASM - dummy = @RadastanScrollUp END SUB @@ -605,7 +656,7 @@ SUB FASTCALL RadastanScrollUp(ByVal lines As Byte) ld b, h ld c, l ; bc = 6144 - lines * 64 ex de, hl ; hl = lines * 64 - ld de, (__RADASTAN_SCR_ADDR) + ld de, (_RadastanScrAddr) add hl, de ; hl = scr_addr + lines * 64 ldir From 8c74c923e724cec973a209f0511d0ea90b61b149 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 4 Sep 2017 00:54:24 +0200 Subject: [PATCH 012/247] add Mandelbrot fractal demo in radastan mode --- examples/zxuno/mandel.bas | 172 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 examples/zxuno/mandel.bas diff --git a/examples/zxuno/mandel.bas b/examples/zxuno/mandel.bas new file mode 100644 index 000000000..00433554a --- /dev/null +++ b/examples/zxuno/mandel.bas @@ -0,0 +1,172 @@ +'Compile with Boriel ZX Basic Compiler +'Parameters: -t -B -a -O3 + +'(C)2015 Miguel Angel Rodriguez Jodar (mcleod_ideafix) +'miguel.angel@zxprojects.com + +'Distributed under GPL license + +#include + +#define XMAX 127 +#define YMAX 95 +#define PART 32 'Initial dimension of a square +#define ESC 15 'Max. iterations for escape time algorithm (hint: we use colours 1-15) + + +declare sub PutPal (entry as ubyte, col as ubyte) +declare function GetPal (entry as ubyte) as ubyte +declare function MakeRGB (r as ubyte, g as ubyte, b as ubyte) as ubyte + +'------------------------------------------------------------------------------ + +Dim i as ubyte +border 0 +cls 'A pixel with value 0 means pixel not processed. Processed pixels have values 1-15 + +RadastanMode(1) + +for i = 0 to 7 'Initialize all 64 entries of the ULAplus palette + PutPal (i, MakeRGB(i,0,0)) 'negro -> rojo + PutPal (i+8, MakeRGB(7,i,0)) 'rojo -> amarillo + PutPal (i+16, MakeRGB(7,7,i/2)) 'amarillo -> blanco + PutPal (i+24, MakeRGB(7,7-i,3)) 'blanco -> magenta + PutPal (i+32, MakeRGB(7-i,0,3)) 'magenta -> azul + PutPal (i+40, MakeRGB(0,i,3)) 'azul -> cyan + PutPal (i+48, MakeRGB(0,7,(7-i)/2)) 'cyan -> verde + PutPal (i+56, MakeRGB(0,7-i,0)) 'verde -> negro +next i + +'Main loop: divide screen into PARTxPART squares and process each one +dim y as ubyte +dim x as uinteger +for y = 0 to YMAX step PART + for x = 0 to XMAX step PART + mandel (x,y,PART) 'First call to recursive function + next x +next y + +'Palette cycling animation +Dim color0 as ubyte +BucleCicloPaleta: +pause 4 +color0 = GetPal(0) +for i = 0 to 62 + PutPal (i, GetPal((i+1) mod 64)) +next i +PutPal (63,color0) + +if inkey$="" then + goto BucleCicloPaleta +end if + +RadastanMode(0) +border 7 +cls +End + +'------------------------------------------------------------------------------ + +function escape (x as uinteger, y as ubyte) as ubyte + dim cr,ci,zr,zi,tr,ti as fixed + dim c as uinteger + dim zrc,zic as fixed + + cr = -2.4+x*3.2/XMAX + ci = -1.2+y*2.4/YMAX + zr = cr + zi = ci + zrc = cr*cr + zic = ci*ci + c = 1 + while (zrc+zic)<4 and c<>ESC + tr = zrc-zic+cr + ti = 2*zr*zi+ci + zr = tr + zi = ti + zrc = zr*zr + zic = zi*zi + c = c + 1 + end while + return c +end function + + +#define PlotR RadastanPlot +#define PixelR RadastanPoint +#define DrawRH(x, y, l, c) RadastanHLine(x, y, x + l - 1, c) + +sub mandel (x as uinteger, y as ubyte, lv as ubyte) + dim co1,co2 as ubyte + dim xx as uinteger + dim yy as ubyte + + 'Base case: compute colour for all pixels of the 2x2 square + if lv = 2 then + co1 = escape (x,y) + RadastanPlot (x,y,co1) + co1 = escape (x+1,y) + RadastanPlot (x+1,y,co1) + co1 = escape (x,y+1) + RadastanPlot (x,y+1,co1) + co1 = escape (x+1,y+1) + RadastanPlot (x+1,y+1,co1) + return + end if + + 'Compute colours for the perimeter of the current square + co1 = RadastanPoint (x,y) 'Read first pixel. If not processed... + if co1 = 0 then '...compute and plot it. + co1 = escape (x,y) + RadastanPlot (x,y,co1) + end if + for yy = y to y+lv-1 + xx = x + do + co2 = PixelR (xx,yy) 'Read current pixel. If not processed... + if co2 = 0 then + co2 = escape (xx,yy) '... compute and plot it + PlotR (xx,yy,co2) + end if + if co1<>co2 then 'Are they different? + goto subdividir 'then, abort perimeter calculation and go directly to subdivision + end if + if yy=y or yy=y+lv-1 then + xx = xx + 1 + else + xx = xx + lv-1 + end if + loop until xx>=x+lv + next yy + + 'If we reach here, all pixels of the perimeter have the same escape time, so... + for yy=y to y+lv-1 '... fill the square with the same colour + DrawRH(x,yy,lv,co1) + next yy + return + + 'If we reach here, we must partition the current square and recursively start over again +subdividir: + mandel (x,y,lv/2) + mandel (x+lv/2,y,lv/2) + mandel (x,y+lv/2,lv/2) + mandel (x+lv/2,y+lv/2,lv/2) +end sub + +'------------------------------------------------------------------------------ + +sub PutPal (entry as ubyte, col as ubyte) + out 48955,entry + out 65339,col +end sub + +function GetPal (entry as ubyte) as ubyte + out 48955,entry + return in 65339 +end function + +function MakeRGB (r as ubyte, g as ubyte, b as ubyte) as ubyte + return ((g band 7) shl 5) bor ((r band 7) shl 2) bor (b band 3) +end function + + From 5fc8f4de4b7f5f189ef4a60f1c1d97ddf7e18cee Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 5 Sep 2017 11:42:21 +0200 Subject: [PATCH 013/247] add missing test orgbad.asm --- tests/functional/orgbad.asm | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 tests/functional/orgbad.asm diff --git a/tests/functional/orgbad.asm b/tests/functional/orgbad.asm new file mode 100644 index 000000000..4b06a8ef0 --- /dev/null +++ b/tests/functional/orgbad.asm @@ -0,0 +1,5 @@ +; Invalid org address +org -1 + +nop + From 1868b01ca5c6dd7e260c9fd7cce50b140a50a763 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 5 Sep 2017 11:42:31 +0200 Subject: [PATCH 014/247] bugfix: test_.py was not reporting failure --- tests/functional/test_.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/functional/test_.py b/tests/functional/test_.py index 8c0e5fbe1..05e825ffb 100755 --- a/tests/functional/test_.py +++ b/tests/functional/test_.py @@ -106,10 +106,12 @@ def main(): try: test.set_temp_dir() test.FOUT = OutputProxy() - doctest.testmod() + result = doctest.testmod() # evals to True on failure + print(result) + return int(result.failed) finally: os.rmdir(test.TEMP_DIR) if __name__ == '__main__': - main() + sys.exit(main()) From 7e9d8d7f8fa67a5c89b95b728fbfd0859646e8ff Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 4 Sep 2017 22:15:52 +0200 Subject: [PATCH 015/247] make code more PEP-8 compliant --- symbols/sentence.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/symbols/sentence.py b/symbols/sentence.py index 1520ddaf5..3bcb4241a 100644 --- a/symbols/sentence.py +++ b/symbols/sentence.py @@ -14,11 +14,11 @@ class SymbolSENTENCE(Symbol): - ''' Defines a BASIC SENTENCE object. e.g. 'BORDER'. - ''' + """ Defines a BASIC SENTENCE object. e.g. 'BORDER'. + """ def __init__(self, keyword, *args): - ''' keyword = 'BORDER', or 'PRINT' - ''' + """ keyword = 'BORDER', or 'PRINT' + """ Symbol.__init__(self, *(x for x in args if not is_null(x))) self.keyword = keyword @@ -28,6 +28,6 @@ def args(self): @property def token(self): - ''' Sentence takes it's token from the keyword not from it's name - ''' + """ Sentence takes it's token from the keyword not from it's name + """ return self.keyword From b0a4cfe91b8343eb4286078ab565ac0e25f67d9a Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 5 Sep 2017 00:40:08 +0200 Subject: [PATCH 016/247] add ON GOTO and ON GOSUB instructions --- ChangeLog | 1 + api/check.py | 19 + arch/zx48k/translator.py | 29 +- keywords.py | 1 + library-asm/ongoto.asm | 31 + tests/functional/ongoto.asm | 1664 +++++++++++++++++++++++++++++++++++ tests/functional/ongoto.bas | 18 + tests/runtime/ongoto.bas | 18 + zxb.py | 2 + zxbparser.py | 38 +- 10 files changed, 1809 insertions(+), 12 deletions(-) create mode 100644 library-asm/ongoto.asm create mode 100644 tests/functional/ongoto.asm create mode 100644 tests/functional/ongoto.bas create mode 100644 tests/runtime/ongoto.bas diff --git a/ChangeLog b/ChangeLog index c81122f9a..35c6f1665 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ ================================================================ Changes from Version 1.6.9 to 1.6.10 +* Added instructions ON .. GOTO and ON .. GOSUB * Added UART library (by yomboprime) for serial communication * Several bugfixes and minor errors * Better code generation diff --git a/api/check.py b/api/check.py index 41ed18329..99161064d 100644 --- a/api/check.py +++ b/api/check.py @@ -167,6 +167,25 @@ def check_pending_labels(ast): return result +def check_and_make_label(lbl, lineno): + """ Checks if the given label (or line number) is valid and, if so, + returns a label object. + :param lbl: Line number of label (string) + :param lineno: Line number in the basic source code for error reporting + :return: Label object or None if error. + """ + if isinstance(lbl, float): + if lbl == int(lbl): + id_ = str(int(lbl)) + else: + syntax_error(lineno, 'Line numbers must be integers.') + return None + else: + id_ = lbl + + return global_.SYMBOL_TABLE.access_label(id_, lineno) + + # ---------------------------------------------------------------------- # Function for checking some arguments # ---------------------------------------------------------------------- diff --git a/arch/zx48k/translator.py b/arch/zx48k/translator.py index 3e26160b3..d2290c5b7 100644 --- a/arch/zx48k/translator.py +++ b/arch/zx48k/translator.py @@ -3,6 +3,7 @@ import functools from collections import OrderedDict +from collections import namedtuple from api.constants import TYPE from api.constants import SCOPE @@ -40,6 +41,8 @@ 'VarTranslator', 'FunctionTranslator'] +JumpTable = namedtuple('JumpTable', ('label', 'addresses')) + class TranslatorVisitor(NodeVisitor): """ This visitor just adds the emit() method. @@ -62,11 +65,13 @@ class TranslatorVisitor(NodeVisitor): LOOPS = [] # Defined LOOPS STRING_LABELS = OrderedDict() + JUMP_TABLES = [] @classmethod def reset(cls): cls.LOOPS = [] # Defined LOOPS cls.STRING_LABELS = OrderedDict() + cls.JUMP_TABLES = [] @property def O_LEVEL(self): @@ -140,6 +145,11 @@ def emit_strings(self): l = '%04X' % (len(str_) & 0xFFFF) # TODO: Universalize for any arch self.emit('vard', label_, [l] + ['%02X' % ord(x) for x in str_]) + def emit_jump_tables(self): + for table_ in self.JUMP_TABLES: + self.emit('vard', table_.label, [str(len(table_.addresses))] + + ['##' + x.mangled for x in table_.addresses]) + def _visit(self, node): self.norm_attr() if isinstance(node, Symbol): @@ -693,7 +703,6 @@ def visit_FOR(self, node): self.emit('label', end_loop) self.LOOPS.pop() - # del loop_label_start, end_loop, loop_label_gt, loop_label_lt, loop_body, loop_continue def visit_GOTO(self, node): self.emit('jump', node.children[0].mangled) @@ -701,6 +710,24 @@ def visit_GOTO(self, node): def visit_GOSUB(self, node): self.emit('call', node.children[0].mangled, 0) + def visit_ON_GOTO(self, node): + table_label = backend.tmp_label() + self.emit('param' + self.TSUFFIX(gl.PTR_TYPE), '#' + table_label) + yield node.children[0] + self.emit('fparam' + self.TSUFFIX(node.children[0].type_), node.children[0].t) + self.emit('call', '__ON_GOTO', 0) + self.JUMP_TABLES.append(JumpTable(table_label, node.children[1:])) + backend.REQUIRES.add('ongoto.asm') + + def visit_ON_GOSUB(self, node): + table_label = backend.tmp_label() + self.emit('param' + self.TSUFFIX(gl.PTR_TYPE), '#' + table_label) + yield node.children[0] + self.emit('fparam' + self.TSUFFIX(node.children[0].type_), node.children[0].t) + self.emit('call', '__ON_GOSUB', 0) + self.JUMP_TABLES.append(JumpTable(table_label, node.children[1:])) + backend.REQUIRES.add('ongoto.asm') + def visit_CHKBREAK(self, node): if self.PREV_TOKEN != node.token: self.emit('fparam' + self.TSUFFIX(gl.PTR_TYPE), node.children[0].t) diff --git a/keywords.py b/keywords.py index b7c6032f9..f158be905 100755 --- a/keywords.py +++ b/keywords.py @@ -77,6 +77,7 @@ 'mod': 'MOD', 'next': 'NEXT', 'not': 'NOT', + 'on': 'ON', 'or': 'OR', 'out': 'OUT', 'over': 'OVER', diff --git a/library-asm/ongoto.asm b/library-asm/ongoto.asm new file mode 100644 index 000000000..9b6759811 --- /dev/null +++ b/library-asm/ongoto.asm @@ -0,0 +1,31 @@ +; ------------------------------------------------------ +; Implements ON .. GOTO +; ------------------------------------------------------ + +__ON_GOSUB: + pop hl + ex (sp), hl ; hl = beginning of table + call __ON_GOTO_START + ret + +__ON_GOTO: + pop hl + ex (sp), hl ; hl = beginning of table + +__ON_GOTO_START: + ; hl = address of jump table + ; a = index (0..255) + cp (hl) ; length of last post + ret nc ; a >= length of last position (out of range) + inc hl + pop de ; removes ret addr from the stack + ld d, 0 + add a, a + ld e, a + rl d + add hl, de + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + jp (hl) diff --git a/tests/functional/ongoto.asm b/tests/functional/ongoto.asm new file mode 100644 index 000000000..8e2fef2de --- /dev/null +++ b/tests/functional/ongoto.asm @@ -0,0 +1,1664 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + call __PRINT_INIT + ld hl, __LABEL0 + push hl + ld a, (_a) + inc a + call __ON_GOTO +__LABEL__10: + ld hl, __LABEL1 + xor a + call __PRINTSTR + call PRINT_EOL +__LABEL__20: + ld hl, __LABEL2 + xor a + call __PRINTSTR + call PRINT_EOL +__LABEL__30: + ld hl, __LABEL3 + xor a + call __PRINTSTR + call PRINT_EOL + ld hl, __LABEL4 + push hl + ld a, (_a) + add a, 2 + call __ON_GOSUB + ld hl, __LABEL5 + push hl + ld a, 1 + call __ON_GOSUB + ld hl, __LABEL6 + xor a + call __PRINTSTR + call PRINT_EOL + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__LABEL__40: + ld hl, __LABEL7 + xor a + call __PRINTSTR + call PRINT_EOL + ret +__LABEL__50: + ld hl, __LABEL8 + xor a + call __PRINTSTR + call PRINT_EOL + ret +__LABEL__60: + ld hl, __LABEL9 + xor a + call __PRINTSTR + call PRINT_EOL + ret +__LABEL__70: + ld hl, __LABEL10 + xor a + call __PRINTSTR + call PRINT_EOL + ret + ld hl, 0 + ld b, h + ld c, l + jp __END_PROGRAM +__LABEL1: + DEFW 0002h + DEFB 31h + DEFB 30h +__LABEL2: + DEFW 0002h + DEFB 32h + DEFB 30h +__LABEL3: + DEFW 0002h + DEFB 33h + DEFB 30h +__LABEL6: + DEFW 0003h + DEFB 45h + DEFB 4Eh + DEFB 44h +__LABEL7: + DEFW 0002h + DEFB 34h + DEFB 30h +__LABEL8: + DEFW 0002h + DEFB 35h + DEFB 30h +__LABEL9: + DEFW 0002h + DEFB 36h + DEFB 30h +__LABEL10: + DEFW 0002h + DEFB 37h + DEFB 30h +__LABEL0: + DEFB 3h + DEFW __LABEL__10 + DEFW __LABEL__20 + DEFW __LABEL__30 +__LABEL4: + DEFB 4h + DEFW __LABEL__40 + DEFW __LABEL__50 + DEFW __LABEL__60 + DEFW __LABEL__70 +__LABEL5: + DEFB 2h + DEFW __LABEL__50 + DEFW __LABEL__60 +#line 1 "ongoto.asm" + ; ------------------------------------------------------ + ; Implements ON .. GOTO + ; ------------------------------------------------------ + +__ON_GOSUB: + pop hl + ex (sp), hl ; hl = beginning of table + call __ON_GOTO_START + ret + +__ON_GOTO: + pop hl + ex (sp), hl ; hl = beginning of table + +__ON_GOTO_START: + ; hl = address of jump table + ; a = index (0..255) + cp (hl) ; length of last post + ret nc ; a >= length of last position (out of range) + inc hl + pop de ; removes ret addr from the stack + ld d, 0 + add a, a + ld e, a + rl d + add hl, de + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + jp (hl) +#line 127 "ongoto.bas" +#line 1 "print.asm" +; vim:ts=4:sw=4:et: + ; PRINT command routine + ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that + +#line 1 "sposn.asm" + ; Printing positioning library. + PROC + LOCAL ECHO_E + +__LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. + ld de, (S_POSN) + ld hl, (MAXX) + or a + sbc hl, de + ex de, hl + ret + + +__SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. + ld hl, (MAXX) + or a + sbc hl, de + ld (S_POSN), hl ; saves it again + ret + + + ECHO_E EQU 23682 + MAXX EQU ECHO_E ; Max X position + 1 + MAXY EQU MAXX + 1 ; Max Y position + 1 + + S_POSN EQU 23688 + POSX EQU S_POSN ; Current POS X + POSY EQU S_POSN + 1 ; Current POS Y + + ENDP + +#line 6 "print.asm" +#line 1 "cls.asm" + ; JUMPS directly to spectrum CLS + ; This routine does not clear lower screen + + ;CLS EQU 0DAFh + + ; Our faster implementation + + + +CLS: + PROC + + LOCAL COORDS + LOCAL __CLS_SCR + LOCAL ATTR_P + LOCAL SCREEN + + ld hl, 0 + ld (COORDS), hl + ld hl, 1821h + ld (S_POSN), hl +__CLS_SCR: + ld hl, SCREEN + ld (hl), 0 + ld d, h + ld e, l + inc de + ld bc, 6144 + ldir + + ; Now clear attributes + + ld a, (ATTR_P) + ld (hl), a + ld bc, 767 + ldir + ret + + COORDS EQU 23677 + SCREEN EQU 16384 ; Default start of the screen (can be changed) + ATTR_P EQU 23693 + ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address + + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines + ; to get the start of the screen + ENDP + +#line 7 "print.asm" +#line 1 "in_screen.asm" + +#line 1 "error.asm" + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 3 "in_screen.asm" + +__IN_SCREEN: + ; Returns NO carry if current coords (D, E) + ; are OUT of the screen limits (MAXX, MAXY) + + PROC + LOCAL __IN_SCREEN_ERR + + ld hl, MAXX + ld a, e + cp (hl) + jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + + ld a, d + inc hl + cp (hl) + ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + ;; ret + ret c ; Return if carry (OK) + +__IN_SCREEN_ERR: +__OUT_OF_SCREEN_ERR: + ; Jumps here if out of screen + ld a, ERROR_OutOfScreen + jp __STOP ; Saves error code and exits + + ENDP +#line 8 "print.asm" +#line 1 "table_jump.asm" + +JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A + add a, a + +JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE + ld e, a + ld d, 0 + +JUMP_HL_PLUS_DE: ; Does JP (HL + DE) + add hl, de + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl +CALL_HL: + jp (hl) + +#line 9 "print.asm" +#line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently +; Parameter: Paper color in A register + +#line 1 "const.asm" + ; Global constants + + P_FLAG EQU 23697 + FLAGS2 EQU 23681 + ATTR_P EQU 23693 ; permanet ATTRIBUTES + ATTR_T EQU 23695 ; temporary ATTRIBUTES + CHARS EQU 23606 ; Pointer to ROM/RAM Charset + UDG EQU 23675 ; Pointer to UDG Charset + MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars + +#line 5 "ink.asm" + +INK: + PROC + LOCAL __SET_INK + LOCAL __SET_INK2 + + ld de, ATTR_P + +__SET_INK: + cp 8 + jr nz, __SET_INK2 + + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + or 7 ; Set bits 0,1,2 to enable transparency + ld (de), a + ret + +__SET_INK2: + ; Another entry. This will set the ink color at location pointer by DE + and 7 ; # Gets color mod 8 + ld b, a ; Saves the color + ld a, (de) + and 0F8h ; Clears previous value + or b + ld (de), a + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + and 0F8h ; Reset bits 0,1,2 sign to disable transparency + ld (de), a ; Store new attr + ret + + ; Sets the INK color passed in A register in the ATTR_T variable +INK_TMP: + ld de, ATTR_T + jp __SET_INK + + ENDP + +#line 10 "print.asm" +#line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently +; Parameter: Paper color in A register + + + +PAPER: + PROC + LOCAL __SET_PAPER + LOCAL __SET_PAPER2 + + ld de, ATTR_P + +__SET_PAPER: + cp 8 + jr nz, __SET_PAPER2 + inc de + ld a, (de) + or 038h + ld (de), a + ret + + ; Another entry. This will set the paper color at location pointer by DE +__SET_PAPER2: + and 7 ; # Remove + rlca + rlca + rlca ; a *= 8 + + ld b, a ; Saves the color + ld a, (de) + and 0C7h ; Clears previous value + or b + ld (de), a + inc de ; Points to MASK_T or MASK_P accordingly + ld a, (de) + and 0C7h ; Resets bits 3,4,5 + ld (de), a + ret + + + ; Sets the PAPER color passed in A register in the ATTR_T variable +PAPER_TMP: + ld de, ATTR_T + jp __SET_PAPER + ENDP + +#line 11 "print.asm" +#line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +FLASH: + ld de, ATTR_P +__SET_FLASH: + ; Another entry. This will set the flash flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + ld b, a ; Saves the color + ld a, (de) + and 07Fh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the FLASH flag passed in A register in the ATTR_T variable +FLASH_TMP: + ld de, ATTR_T + jr __SET_FLASH + +#line 12 "print.asm" +#line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +BRIGHT: + ld de, ATTR_P + +__SET_BRIGHT: + ; Another entry. This will set the bright flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + rrca + ld b, a ; Saves the color + ld a, (de) + and 0BFh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable +BRIGHT_TMP: + ld de, ATTR_T + jr __SET_BRIGHT + +#line 13 "print.asm" +#line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently +; Parameter: OVER flag in bit 0 of A register +#line 1 "copy_attr.asm" + + +#line 4 "/home/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" + + + +COPY_ATTR: + ; Just copies current permanent attribs to temporal attribs + ; and sets print mode + PROC + + LOCAL INVERSE1 + LOCAL __REFRESH_TMP + + INVERSE1 EQU 02Fh + + ld hl, (ATTR_P) + ld (ATTR_T), hl + + ld hl, FLAGS2 + call __REFRESH_TMP + + ld hl, P_FLAG + call __REFRESH_TMP + + +__SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) + + + LOCAL TABLE + LOCAL CONT2 + + rra ; Over bit to carry + ld a, (FLAGS2) + rla ; Over bit in bit 1, Over2 bit in bit 2 + and 3 ; Only bit 0 and 1 (OVER flag) + + ld c, a + ld b, 0 + + ld hl, TABLE + add hl, bc + ld a, (hl) + ld (PRINT_MODE), a + + ld hl, (P_FLAG) + xor a ; NOP -> INVERSE0 + bit 2, l + jr z, CONT2 + ld a, INVERSE1 ; CPL -> INVERSE1 + +CONT2: + ld (INVERSE_MODE), a + ret + +TABLE: + nop ; NORMAL MODE + xor (hl) ; OVER 1 MODE + and (hl) ; OVER 2 MODE + or (hl) ; OVER 3 MODE + +#line 65 "/home/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" + +__REFRESH_TMP: + ld a, (hl) + and 10101010b + ld c, a + rra + or c + ld (hl), a + ret + + ENDP + +#line 4 "over.asm" + + +OVER: + PROC + + ld c, a ; saves it for later + and 2 + ld hl, FLAGS2 + res 1, (HL) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 ; # Convert to 0/1 + add a, a; # Shift left 1 bit for permanent + + ld hl, P_FLAG + res 1, (hl) + or (hl) + ld (hl), a + ret + + ; Sets OVER flag in P_FLAG temporarily +OVER_TMP: + ld c, a ; saves it for later + and 2 ; gets bit 1; clears carry + rra + ld hl, FLAGS2 + res 0, (hl) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 + ld hl, P_FLAG + res 0, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 14 "print.asm" +#line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently +; Parameter: INVERSE flag in bit 0 of A register + + + +INVERSE: + PROC + + and 1 ; # Convert to 0/1 + add a, a; # Shift left 3 bits for permanent + add a, a + add a, a + ld hl, P_FLAG + res 3, (hl) + or (hl) + ld (hl), a + ret + + ; Sets INVERSE flag in P_FLAG temporarily +INVERSE_TMP: + and 1 + add a, a + add a, a; # Shift left 2 bits for temporary + ld hl, P_FLAG + res 2, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 15 "print.asm" +#line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently +; Parameter: BOLD flag in bit 0 of A register + + +BOLD: + PROC + + and 1 + rlca + rlca + rlca + ld hl, FLAGS2 + res 3, (HL) + or (hl) + ld (hl), a + ret + + ; Sets BOLD flag in P_FLAG temporarily +BOLD_TMP: + and 1 + rlca + rlca + ld hl, FLAGS2 + res 2, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 16 "print.asm" +#line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently +; Parameter: ITALIC flag in bit 0 of A register + + +ITALIC: + PROC + + and 1 + rrca + rrca + rrca + ld hl, FLAGS2 + res 5, (HL) + or (hl) + ld (hl), a + ret + + ; Sets ITALIC flag in P_FLAG temporarily +ITALIC_TMP: + and 1 + rrca + rrca + rrca + rrca + ld hl, FLAGS2 + res 4, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 17 "print.asm" + +#line 1 "attr.asm" + ; Attribute routines +; vim:ts=4:et:sw: + + + + + + + +__ATTR_ADDR: + ; calc start address in DE (as (32 * d) + e) + ; Contributed by Santiago Romero at http://www.speccy.org + ld h, 0 ; 7 T-States + ld a, d ; 4 T-States + add a, a ; a * 2 ; 4 T-States + add a, a ; a * 4 ; 4 T-States + ld l, a ; HL = A * 4 ; 4 T-States + + add hl, hl ; HL = A * 8 ; 15 T-States + add hl, hl ; HL = A * 16 ; 15 T-States + add hl, hl ; HL = A * 32 ; 15 T-States + + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) + add hl, de + + ld de, (SCREEN_ADDR) ; Adds the screen address + add hl, de + + ; Return current screen address in HL + ret + + + ; Sets the attribute at a given screen coordinate (D, E). + ; The attribute is taken from the ATTR_T memory variable + ; Used by PRINT routines +SET_ATTR: + + ; Checks for valid coords + call __IN_SCREEN + ret nc + +__SET_ATTR: + ; Internal __FASTCALL__ Entry used by printing routines + PROC + + call __ATTR_ADDR + ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T + + ld a, d + and (hl) + ld c, a ; C = current screen color, masked + + ld a, d + cpl ; Negate mask + and e ; Mask current attributes + or c ; Mix them + ld (hl), a ; Store result in screen + + ret + + ENDP + + +#line 19 "print.asm" + + ; Putting a comment starting with @INIT
+ ; will make the compiler to add a CALL to
+ ; It is useful for initialization routines. + + +__PRINT_INIT: ; To be called before program starts (initializes library) + PROC + + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + + ld hl, 1821h + ld (MAXX), hl ; Sets current maxX and maxY + + xor a + ld (FLAGS2), a + + ret + + +__PRINTCHAR: ; Print character store in accumulator (A register) + ; Modifies H'L', B'C', A'F', D'E', A + + LOCAL PO_GR_1 + + LOCAL __PRCHAR + LOCAL __PRINT_CONT + LOCAL __PRINT_CONT2 + LOCAL __PRINT_JUMP + LOCAL __SRCADDR + LOCAL __PRINT_UDG + LOCAL __PRGRAPH + LOCAL __PRINT_START + + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 + +__PRINT_JUMP: + jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively + +__PRINT_START: + cp ' ' + jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones + + exx ; Switch to alternative registers + ex af, af' ; Saves a value (char to print) for later + + call __LOAD_S_POSN + + ; At this point we have the new coord + ld hl, (SCREEN_ADDR) + + ld a, d + ld c, a ; Saves it for later + + and 0F8h ; Masks 3 lower bit ; zy + ld d, a + + ld a, c ; Recovers it + and 07h ; MOD 7 ; y1 + rrca + rrca + rrca + + or e + ld e, a + add hl, de ; HL = Screen address + DE + ex de, hl ; DE = Screen address + + ex af, af' + + cp 80h ; Is it an UDG or a ? + jp c, __SRCADDR + + cp 90h + jp nc, __PRINT_UDG + + ; Print a 8 bit pattern (80h to 8Fh) + + ld b, a + call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 + ld hl, MEM0 + jp __PRGRAPH + + PO_GR_1 EQU 0B38h + +__PRINT_UDG: + sub 90h ; Sub ASC code + ld bc, (UDG) + jp __PRGRAPH0 + + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source +__SRCADDR: + ld bc, (CHARS) + +__PRGRAPH0: + add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org + ld l, a + ld h, 0 ; HL = a * 2 (accumulator) + add hl, hl + add hl, hl ; HL = a * 8 + add hl, bc ; HL = CHARS address + +__PRGRAPH: + ex de, hl ; HL = Write Address, DE = CHARS address + bit 2, (iy + $47) + call nz, __BOLD + bit 4, (iy + $47) + call nz, __ITALIC + ld b, 8 ; 8 bytes per char +__PRCHAR: + ld a, (de) ; DE *must* be ALWAYS source, and HL destiny + +PRINT_MODE: ; Which operation is used to write on the screen + ; Set it with: + ; LD A, + ; LD (PRINT_MODE), A + ; + ; Available opertions: + ; NORMAL: 0h --> NOP ; OVER 0 + ; XOR : AEh --> XOR (HL) ; OVER 1 + ; OR : B6h --> OR (HL) ; PUTSPRITE + ; AND : A6h --> AND (HL) ; PUTMASK + nop ; + +INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 + nop ; 2F -> CPL -> INVERSE 1 + + ld (hl), a + + inc de + inc h ; Next line + djnz __PRCHAR + + call __LOAD_S_POSN + push de + call __SET_ATTR + pop de + inc e ; COL = COL + 1 + ld hl, (MAXX) + ld a, e + dec l ; l = MAXX + cp l ; Lower than max? + jp c, __PRINT_CONT; Nothing to do + call __PRINT_EOL1 + exx ; counteracts __PRINT_EOL1 exx + jp __PRINT_CONT2 + +__PRINT_CONT: + call __SAVE_S_POSN + +__PRINT_CONT2: + exx + ret + + ; ------------- SPECIAL CHARS (< 32) ----------------- + +__PRINT_SPECIAL: ; Jumps here if it is a special char + exx + ld hl, __PRINT_TABLE + jp JUMP_HL_PLUS_2A + + +PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence + exx + +__PRINT_0Dh: ; Called WHEN printing CHR$(13) + call __LOAD_S_POSN + +__PRINT_EOL1: ; Another entry called from PRINT when next line required + ld e, 0 + +__PRINT_EOL2: + ld a, d + inc a + +__PRINT_AT1_END: + ld hl, (MAXY) + cp l + jr c, __PRINT_EOL_END ; Carry if (MAXY) < d + xor a + +__PRINT_EOL_END: + ld d, a + +__PRINT_AT2_END: + call __SAVE_S_POSN + exx + ret + +__PRINT_COM: + exx + push hl + push de + push bc + call PRINT_COMMA + pop bc + pop de + pop hl + ret + +__PRINT_TAB: + ld hl, __PRINT_TAB1 + jp __PRINT_SET_STATE + +__PRINT_TAB1: + ld (MEM0), a + ld hl, __PRINT_TAB2 + ld (PRINT_JUMP_STATE), hl + ret + +__PRINT_TAB2: + ld a, (MEM0) ; Load tab code (ignore the current one) + push hl + push de + push bc + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + call PRINT_TAB + pop bc + pop de + pop hl + ret + +__PRINT_NOP: +__PRINT_RESTART: + ld hl, __PRINT_START + jp __PRINT_SET_STATE + +__PRINT_AT: + ld hl, __PRINT_AT1 + +__PRINT_SET_STATE: + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + exx + ret + +__PRINT_AT1: ; Jumps here if waiting for 1st parameter + exx + ld hl, __PRINT_AT2 + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + jp __PRINT_AT1_END + +__PRINT_AT2: + exx + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + ld e, a + ld hl, (MAXX) + cp (hl) + jr c, __PRINT_AT2_END + jr __PRINT_EOL1 + +__PRINT_DEL: + call __LOAD_S_POSN ; Gets current screen position + dec e + ld a, -1 + cp e + jp nz, __PRINT_AT2_END + ld hl, (MAXX) + ld e, l + dec e + dec e + dec d + cp d + jp nz, __PRINT_AT2_END + ld d, h + dec d + jp __PRINT_AT2_END + +__PRINT_INK: + ld hl, __PRINT_INK2 + jp __PRINT_SET_STATE + +__PRINT_INK2: + exx + call INK_TMP + jp __PRINT_RESTART + +__PRINT_PAP: + ld hl, __PRINT_PAP2 + jp __PRINT_SET_STATE + +__PRINT_PAP2: + exx + call PAPER_TMP + jp __PRINT_RESTART + +__PRINT_FLA: + ld hl, __PRINT_FLA2 + jp __PRINT_SET_STATE + +__PRINT_FLA2: + exx + call FLASH_TMP + jp __PRINT_RESTART + +__PRINT_BRI: + ld hl, __PRINT_BRI2 + jp __PRINT_SET_STATE + +__PRINT_BRI2: + exx + call BRIGHT_TMP + jp __PRINT_RESTART + +__PRINT_INV: + ld hl, __PRINT_INV2 + jp __PRINT_SET_STATE + +__PRINT_INV2: + exx + call INVERSE_TMP + jp __PRINT_RESTART + +__PRINT_OVR: + ld hl, __PRINT_OVR2 + jp __PRINT_SET_STATE + +__PRINT_OVR2: + exx + call OVER_TMP + jp __PRINT_RESTART + +__PRINT_BOLD: + ld hl, __PRINT_BOLD2 + jp __PRINT_SET_STATE + +__PRINT_BOLD2: + exx + call BOLD_TMP + jp __PRINT_RESTART + +__PRINT_ITA: + ld hl, __PRINT_ITA2 + jp __PRINT_SET_STATE + +__PRINT_ITA2: + exx + call ITALIC_TMP + jp __PRINT_RESTART + + +__BOLD: + push hl + ld hl, MEM0 + ld b, 8 +__BOLD_LOOP: + ld a, (de) + ld c, a + rlca + or c + ld (hl), a + inc hl + inc de + djnz __BOLD_LOOP + pop hl + ld de, MEM0 + ret + + +__ITALIC: + push hl + ld hl, MEM0 + ex de, hl + ld bc, 8 + ldir + ld hl, MEM0 + srl (hl) + inc hl + srl (hl) + inc hl + srl (hl) + inc hl + inc hl + inc hl + sla (hl) + inc hl + sla (hl) + inc hl + sla (hl) + pop hl + ld de, MEM0 + ret + +PRINT_COMMA: + call __LOAD_S_POSN + ld a, e + and 16 + add a, 16 + +PRINT_TAB: + PROC + LOCAL LOOP, CONTINUE + + inc a + call __LOAD_S_POSN ; e = current row + ld d, a + ld a, e + cp 21h + jr nz, CONTINUE + ld e, -1 +CONTINUE: + ld a, d + inc e + sub e ; A = A - E + and 31 ; + ret z ; Already at position E + ld b, a +LOOP: + ld a, ' ' + call __PRINTCHAR + djnz LOOP + ret + ENDP + +PRINT_AT: ; CHanges cursor to ROW, COL + ; COL in A register + ; ROW in stack + + pop hl ; Ret address + ex (sp), hl ; callee H = ROW + ld l, a + ex de, hl + + call __IN_SCREEN + ret nc ; Return if out of screen + + jp __SAVE_S_POSN + + LOCAL __PRINT_COM + LOCAL __BOLD + LOCAL __BOLD_LOOP + LOCAL __ITALIC + LOCAL __PRINT_EOL1 + LOCAL __PRINT_EOL2 + LOCAL __PRINT_AT1 + LOCAL __PRINT_AT2 + LOCAL __PRINT_AT2_END + LOCAL __PRINT_BOLD + LOCAL __PRINT_BOLD2 + LOCAL __PRINT_ITA + LOCAL __PRINT_ITA2 + LOCAL __PRINT_INK + LOCAL __PRINT_PAP + LOCAL __PRINT_SET_STATE + LOCAL __PRINT_TABLE + LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 + +__PRINT_TABLE: ; Jump table for 0 .. 22 codes + + DW __PRINT_NOP ; 0 + DW __PRINT_NOP ; 1 + DW __PRINT_NOP ; 2 + DW __PRINT_NOP ; 3 + DW __PRINT_NOP ; 4 + DW __PRINT_NOP ; 5 + DW __PRINT_COM ; 6 COMMA + DW __PRINT_NOP ; 7 + DW __PRINT_DEL ; 8 DEL + DW __PRINT_NOP ; 9 + DW __PRINT_NOP ; 10 + DW __PRINT_NOP ; 11 + DW __PRINT_NOP ; 12 + DW __PRINT_0Dh ; 13 + DW __PRINT_BOLD ; 14 + DW __PRINT_ITA ; 15 + DW __PRINT_INK ; 16 + DW __PRINT_PAP ; 17 + DW __PRINT_FLA ; 18 + DW __PRINT_BRI ; 19 + DW __PRINT_INV ; 20 + DW __PRINT_OVR ; 21 + DW __PRINT_AT ; 22 AT + DW __PRINT_TAB ; 23 TAB + + ENDP + + +#line 128 "ongoto.bas" +#line 1 "printstr.asm" + + + +#line 1 "free.asm" +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 5 "printstr.asm" + + ; PRINT command routine + ; Prints string pointed by HL + +PRINT_STR: +__PRINTSTR: ; __FASTCALL__ Entry to print_string + PROC + LOCAL __PRINT_STR_LOOP + LOCAL __PRINT_STR_END + + ld d, a ; Saves A reg (Flag) for later + + ld a, h + or l + ret z ; Return if the pointer is NULL + + push hl + + ld c, (hl) + inc hl + ld b, (hl) + inc hl ; BC = LEN(a$); HL = &a$ + +__PRINT_STR_LOOP: + ld a, b + or c + jr z, __PRINT_STR_END ; END if BC (counter = 0) + + ld a, (hl) + call __PRINTCHAR + inc hl + dec bc + jp __PRINT_STR_LOOP + +__PRINT_STR_END: + pop hl + ld a, d ; Recovers A flag + or a ; If not 0 this is a temporary string. Free it + ret z + jp __MEM_FREE ; Frees str from heap and return from there + +__PRINT_STR: + ; Fastcall Entry + ; It ONLY prints strings + ; HL = String start + ; BC = String length (Number of chars) + push hl ; Push str address for later + ld d, a ; Saves a FLAG + jp __PRINT_STR_LOOP + + ENDP + +#line 129 "ongoto.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 01h +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ongoto.bas b/tests/functional/ongoto.bas new file mode 100644 index 000000000..fcbd0c9f0 --- /dev/null +++ b/tests/functional/ongoto.bas @@ -0,0 +1,18 @@ + +DIM a as UBYte = 1 +ON a + 1 GOTO 10, 20, 30 + +10 PRINT "10" +20 PRINT "20" +30 PRINT "30" + +ON a + 2 GOSUB 40, 50, 60, 70 +ON 1 GOSUB 50, 60 +PRINT "END" + +END +40 PRINT "40": RETURN +50 PRINT "50": RETURN +60 PRINT "60": RETURN +70 PRINT "70": RETURN + diff --git a/tests/runtime/ongoto.bas b/tests/runtime/ongoto.bas new file mode 100644 index 000000000..fcbd0c9f0 --- /dev/null +++ b/tests/runtime/ongoto.bas @@ -0,0 +1,18 @@ + +DIM a as UBYte = 1 +ON a + 1 GOTO 10, 20, 30 + +10 PRINT "10" +20 PRINT "20" +30 PRINT "30" + +ON a + 2 GOSUB 40, 50, 60, 70 +ON 1 GOSUB 50, 60 +PRINT "END" + +END +40 PRINT "40": RETURN +50 PRINT "50": RETURN +60 PRINT "60": RETURN +70 PRINT "70": RETURN + diff --git a/zxb.py b/zxb.py index 06ac67694..8a3c7a747 100755 --- a/zxb.py +++ b/zxb.py @@ -250,6 +250,8 @@ def main(args=None): # Emits default constant strings translator.emit_strings() + # Emits jump tables + translator.emit_jump_tables() if OPTIONS.emitBackend.value: with open_file(OPTIONS.outputFileName.value, 'wt', 'utf-8') as output_file: diff --git a/zxbparser.py b/zxbparser.py index 48e9f091f..cdddff7ae 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -24,6 +24,7 @@ from api.errmsg import syntax_error from api.errmsg import warning +from api.check import check_and_make_label from api.check import common_type from api.check import is_dynamic from api.check import is_null @@ -1055,17 +1056,7 @@ def p_goto(p): | goto ID CO | goto ID NEWLINE """ - if isinstance(p[2], float): - if p[2] == int(p[2]): - id_ = str(int(p[2])) - else: - syntax_error(p.lineno(1), 'Line numbers must be integers.') - p[0] = None - return - else: - id_ = p[2] - - entry = SYMBOL_TABLE.access_label(id_, p.lineno(2)) + entry = check_and_make_label(p[2], p.lineno(2)) if entry is not None: p[0] = make_sentence(p[1].upper(), entry) else: @@ -1779,6 +1770,31 @@ def p_print_list_tab(p): make_typecast(TYPE.ubyte, p[2], p.lineno(1))) +def p_on_goto(p): + """ statement : ON expr goto label_list CO + | ON expr goto label_list NEWLINE + """ + expr = make_typecast(TYPE.ubyte, p[2], p.lineno(1)) + p[0] = make_sentence('ON_' + p[3], expr, *p[4]) + + +def p_label_list(p): + """ label_list : ID + | NUMBER + """ + entry = check_and_make_label(p[1], p.lineno(1)) + p[0] = [entry] + + +def p_label_list_list(p): + """ label_list : label_list COMMA ID + | label_list COMMA NUMBER + """ + p[0] = p[1] + entry = check_and_make_label(p[3], p.lineno(3)) + p[1].append(entry) + + def p_return(p): """ statement : RETURN CO | RETURN NEWLINE From 066ac05120242cb3a8b13d90f5a1ce92f1843754 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 4 Sep 2017 15:51:38 +0200 Subject: [PATCH 017/247] cleanup: make code more PEP-8 compliant --- prepro/args.py | 8 ++++---- prepro/definestable.py | 32 ++++++++++++++++---------------- prepro/exceptions.py | 4 ++-- prepro/id_.py | 12 ++++++------ prepro/macrocall.py | 20 ++++++++++---------- 5 files changed, 38 insertions(+), 38 deletions(-) diff --git a/prepro/args.py b/prepro/args.py index c18da973c..afc656f52 100644 --- a/prepro/args.py +++ b/prepro/args.py @@ -6,8 +6,8 @@ class Arg(object): - ''' Implements an argument (a list of tokens and macrocalls) - ''' + """ Implements an argument (a list of tokens and macrocalls) + """ def __init__(self, value=None, table=None): self.table = table self.value = [] @@ -43,8 +43,8 @@ def __iter__(self): class ArgList(object): - ''' Implements an arglist - ''' + """ Implements an arglist + """ def __init__(self, table): self.table = table self.value = [] diff --git a/prepro/definestable.py b/prepro/definestable.py index dfb0c0cf8..8d4b16f04 100644 --- a/prepro/definestable.py +++ b/prepro/definestable.py @@ -2,9 +2,9 @@ # -*- coding: utf-8 -*- # vim: ts=4:sw=4:et: -''' Class for a Table of Defines. +""" Class for a Table of Defines. Each identifier has a dictionary entry. -''' +""" import sys import re @@ -18,20 +18,20 @@ class DefinesTable(object): - ''' A class which will store + """ A class which will store define labels, and its values. It will also susbtitute the current value of a label for the given value. - ''' + """ def __init__(self): - ''' Initializes table - ''' + """ Initializes table + """ self.table = {} def define(self, id_, lineno, value='', fname=None, args=None): - ''' Defines the value of a macro. + """ Defines the value of a macro. Issues a warning if the macro is already defined. - ''' + """ if fname is None: if CURRENT_FILE: fname = CURRENT_FILE[-1] @@ -45,9 +45,9 @@ def define(self, id_, lineno, value='', fname=None, args=None): self.set(id_, lineno, value, fname, args) def set(self, id_, lineno, value='', fname=None, args=None): - ''' Like the above, but issues no warning on duplicate macro + """ Like the above, but issues no warning on duplicate macro definitions. - ''' + """ if fname is None: if CURRENT_FILE: fname = CURRENT_FILE[-1] @@ -60,21 +60,21 @@ def undef(self, id_): del self.table[id_] def defined(self, id_): - ''' Returns if the given ID + """ Returns if the given ID is defined - ''' + """ return id_.strip() in self.table.keys() def __getitem__(self, key): - ''' Returns the ID instance given it's + """ Returns the ID instance given it's _id. If it does not exist, return the _id itself. - ''' + """ return self.table.get(key.strip(), key) def __setitem__(self, key, value): - ''' Assigns the value to the given table entry - ''' + """ Assigns the value to the given table entry + """ k = key.strip() if not RE_ID.match(k): raise PreprocError('"%s" must be an identifier' % key, None) diff --git a/prepro/exceptions.py b/prepro/exceptions.py index 7112ccc62..84b096db5 100644 --- a/prepro/exceptions.py +++ b/prepro/exceptions.py @@ -3,8 +3,8 @@ class PreprocError(Exception): - ''' Denotes an exception in de preprocessor - ''' + """ Denotes an exception in de preprocessor + """ def __init__(self, msg, lineno): self.message = msg self.lineno = lineno diff --git a/prepro/id_.py b/prepro/id_.py index bd6ee8f1a..289e34cf0 100644 --- a/prepro/id_.py +++ b/prepro/id_.py @@ -2,9 +2,9 @@ # -*- coding: utf-8 -*- # vim: ts=4:sw=4:et: -__doc__ = ''' A class for an identifier parsed by the preprocessor. +__doc__ = """ A class for an identifier parsed by the preprocessor. It contains it's name, arguments and macro value. -''' +""" import sys @@ -15,9 +15,9 @@ class ID(object): - ''' This class represents an identifier. It's stores a string + """ This class represents an identifier. It's stores a string (the ID name and value by default). - ''' + """ def __init__(self, id_, args=None, value=None, lineno=None, fname=None): if fname is None: fname = CURRENT_FILE[-1] @@ -42,9 +42,9 @@ def __str__(self): return self.name def __dumptable(self, table): - ''' Dumps table on screen + """ Dumps table on screen for debugging purposes - ''' + """ for x in table.table.keys(): sys.stdout.write("{0}\t<--- {1} {2}".format(x, table[x], type(table[x]))) if isinstance(table[x], ID): diff --git a/prepro/macrocall.py b/prepro/macrocall.py index 3c34a0237..ce1049790 100644 --- a/prepro/macrocall.py +++ b/prepro/macrocall.py @@ -8,29 +8,29 @@ class MacroCall(object): - ''' A call to a macro, stored in an object. + """ A call to a macro, stored in an object. Every time the macro() is called, the macro returns it value. - ''' + """ def __init__(self, lineno, table, id_, args=None): - ''' Initializes the object with the ID table, the ID name and + """ Initializes the object with the ID table, the ID name and optionally, the passed args. - ''' + """ self.table = table self.id_ = id_ self.callargs = args self.lineno = lineno def eval(self, arg): - ''' Evaluates a given argument. The token will be returned by default + """ Evaluates a given argument. The token will be returned by default "as is", except if it's a macrocall. In such case it will be evaluated recursively. - ''' + """ return str(arg()) # Evaluate the arg (could be a macrocall) def __call__(self, symbolTable=None): - ''' Execute the macro call using LAZY evaluation - ''' + """ Execute the macro call using LAZY evaluation + """ __DEBUG__("evaluating '%s'" % self.id_, 2) if symbolTable is None: symbolTable = self.table @@ -87,8 +87,8 @@ def __call__(self, symbolTable=None): return tmp def is_defined(self, symbolTable=None): - ''' True if this macro has been defined - ''' + """ True if this macro has been defined + """ if symbolTable is None: symbolTable = self.table From 803600d9032a02159b420acac69cc042d71ca2d7 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 4 Sep 2017 17:41:47 +0200 Subject: [PATCH 018/247] use current file dir for includes When using #include "file", the current file directory will be first us to get the file, otherwise, use INCLUDE PATH. When using #include then only INCLUDE PATH used, *even if the file exist locally*. The compiler no longer looks for include files in the PATH or other places. This change might break previous versions (should not). --- zxbpp.py | 92 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 53 insertions(+), 39 deletions(-) diff --git a/zxbpp.py b/zxbpp.py index 12e30c1de..433a31ef0 100755 --- a/zxbpp.py +++ b/zxbpp.py @@ -71,8 +71,9 @@ def init(): global_.FILENAME = '(stdin)' OUTPUT = '' INCLUDED = {} - CURRENT_DIR = get_include_path() - INCLUDEPATH = ('library', 'library-asm') + CURRENT_DIR = '' + pwd = get_include_path() + INCLUDEPATH = [os.path.join(pwd, 'library'), os.path.join(pwd, 'library-asm')] ENABLED = True IFDEFS = [] global_.has_errors = 0 @@ -117,20 +118,20 @@ def setMode(mode): LEXER = zxbpplex.Lexer() -def search_filename(fname, lineno): - """ Search a filename into the list of the include path +def search_filename(fname, lineno, local_first): + """ Search a filename into the list of the include path. + If local_first is true, it will try first in the current directory of + the file being analyzed. """ fname = sanitize_file(fname) - include_path_dirs = OPTIONS.include_path.value.split(':') if OPTIONS.include_path.value else [] - - for i in INCLUDEPATH: - if not os.path.isabs(i): - for j in [CURRENT_DIR] + include_path_dirs + os.environ['PATH'].split(os.pathsep): - path = os.path.join(j, i, fname) - if os.path.exists(path): - return path - else: - path = os.path.join(i, fname) + i_path = [CURRENT_DIR] + INCLUDEPATH if local_first else INCLUDEPATH + i_path.extend(OPTIONS.include_path.value.split(':') if OPTIONS.include_path.value else []) + if os.path.isabs(fname): + if os.path.isfile(fname): + return fname + else: + for dir_ in i_path: + path = os.path.join(dir_, fname) if os.path.exists(path): return path @@ -138,11 +139,17 @@ def search_filename(fname, lineno): return '' -def include_file(filename, lineno): - """ Writes down that "filename" was included at the current file, - at line +def include_file(filename, lineno, local_first): + """ Performs a file inclusion (#include) in the preprocessor. + Writes down that "filename" was included at the current file, + at line . + + If local_first is True, then it will first search the file in the + local path before looking for it in the include path chain. + This is used when doing a #include "filename". """ - filename = sanitize_file(filename) + global CURRENT_DIR + filename = search_filename(filename, lineno, local_first) if filename not in INCLUDED.keys(): INCLUDED[filename] = [] @@ -150,15 +157,25 @@ def include_file(filename, lineno): INCLUDED[filename].append((CURRENT_FILE[-1], lineno)) CURRENT_FILE.append(filename) + CURRENT_DIR = os.path.dirname(filename) return LEXER.include(filename) -def include_once(filename, lineno): - """ Do as above only in file not already included +def include_once(filename, lineno, local_first): + """ Performs a file inclusion (#include) in the preprocessor. + Writes down that "filename" was included at the current file, + at line . + + The file is ignored if it was previuosly included (a warning will + be emitted though). + + If local_first is True, then it will first search the file in the + local path before looking for it in the include path chain. + This is used when doing a #include "filename". """ - filename = sanitize_file(filename) + filename = search_filename(filename, lineno, local_first) if filename not in INCLUDED.keys(): # If not already included - return include_file(filename, lineno) # include it and return + return include_file(filename, lineno, local_first) # include it and return # Now checks if the file has been included more than once if len(INCLUDED[filename]) > 1: @@ -281,7 +298,7 @@ def p_include(p): """ include : INCLUDE STRING """ if ENABLED: - p[0] = include_file(p[2], p.lineno(2)) + p[0] = include_file(p[2], p.lineno(2), local_first=True) else: p[0] = [] p.lexer.next_token = '_ENDFILE_' @@ -291,21 +308,17 @@ def p_include_fname(p): """ include : INCLUDE FILENAME """ if ENABLED: - l = p.lineno(2) - fname = search_filename(p[2], l) - if fname: - p[0] = include_file(search_filename(p[2], l), l) - return - - p[0] = [] - p.lexer.next_token = '_ENDFILE_' + p[0] = include_file(p[2], p.lineno(2), local_first=False) + else: + p[0] = [] + p.lexer.next_token = '_ENDFILE_' def p_include_once(p): """ include_once : INCLUDE ONCE STRING """ if ENABLED: - p[0] = include_once(p[3], p.lineno(3)) + p[0] = include_once(p[3], p.lineno(3), local_first=True) else: p[0] = [] @@ -319,10 +332,9 @@ def p_include_once_fname(p): p[0] = [] if ENABLED: - l = p.lineno(3) - fname = search_filename(p[3], l) - if fname: - p[0] = include_once(fname, l) + p[0] = include_once(p[3], p.lineno(3), local_first=False) + else: + p[0] = [] if not p[0]: p.lexer.next_token = '_ENDFILE_' @@ -710,7 +722,7 @@ def filter_(input_, filename='', state='INITIAL'): def main(argv): - global OUTPUT, ID_TABLE, ENABLED + global OUTPUT, ID_TABLE, ENABLED, CURRENT_DIR ENABLED = True OUTPUT = '' @@ -719,18 +731,20 @@ def main(argv): CURRENT_FILE.append(argv[0]) else: CURRENT_FILE.append(global_.FILENAME) + CURRENT_DIR = os.path.dirname(CURRENT_FILE[-1]) if OPTIONS.Sinclair.value: - included_file = search_filename('sinclair.bas', 0) + included_file = search_filename('sinclair.bas', 0, local_first=False) if not included_file: return - OUTPUT += include_once(included_file, 0) + OUTPUT += include_once(included_file, 0, local_first=False) if len(OUTPUT) and OUTPUT[-1] != '\n': OUTPUT += '\n' parser.parse(lexer=LEXER, debug=OPTIONS.Debug.value > 2) CURRENT_FILE.pop() + CURRENT_DIR = os.path.dirname(CURRENT_FILE[-1]) prev_file = global_.FILENAME global_.FILENAME = CURRENT_FILE[-1] From ded25593b3dadd5dc0607a7d769733366be8fbe6 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 5 Sep 2017 13:19:43 +0200 Subject: [PATCH 019/247] bugfix: uses -e parameter in BASIC tests The -e parameter was being ignored for BASIC test. Fixed --- tests/functional/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/test.py b/tests/functional/test.py index a10475445..b6e4c1315 100755 --- a/tests/functional/test.py +++ b/tests/functional/test.py @@ -196,7 +196,7 @@ def _get_testbas_options(fname): - the test .asm file that will be generated - the extension of the file (normally .asm) """ - prep = ['-e', '/dev/null'] if CLOSE_STDERR else [] + prep = ['-e', '/dev/null'] if CLOSE_STDERR else ['-e', STDERR] options = ['-O1'] match = reOPT.match(getName(fname)) From 929c020e3c56c1232ca5efdc087b528eaffc079d Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 5 Sep 2017 13:20:11 +0200 Subject: [PATCH 020/247] refact: uses global api.warning function --- tests/functional/asmprepro.asm | 17 +++++++++++++++++ tests/functional/asmprepro.bin | Bin 0 -> 5 bytes tests/functional/test_.py | 4 ++++ zxbasmpplex.py | 8 ++------ 4 files changed, 23 insertions(+), 6 deletions(-) create mode 100644 tests/functional/asmprepro.asm create mode 100644 tests/functional/asmprepro.bin diff --git a/tests/functional/asmprepro.asm b/tests/functional/asmprepro.asm new file mode 100644 index 000000000..ba916ba87 --- /dev/null +++ b/tests/functional/asmprepro.asm @@ -0,0 +1,17 @@ +; Test recursive inclusion in ASM files + +#ifndef __I1__ +# ifndef __I2__ +# define __I2__ +nop ; I2 +# include "asmprepro.asm" +# endif +# define __I1__ +nop ; I1 +# include "asmprepro.asm" +# undef __I1__ +nop +#endif + + + diff --git a/tests/functional/asmprepro.bin b/tests/functional/asmprepro.bin new file mode 100644 index 0000000000000000000000000000000000000000..40b450dd9d8187f90cf9f13a80c3ded26f8ecfd7 GIT binary patch literal 5 KcmZQz00IC21pom6 literal 0 HcmV?d00001 diff --git a/tests/functional/test_.py b/tests/functional/test_.py index 05e825ffb..ad42bd532 100755 --- a/tests/functional/test_.py +++ b/tests/functional/test_.py @@ -84,6 +84,10 @@ orgbad.asm:2: Memory ORG out of range [0 .. 65535]. Current value: -1 >>> process_file('defsbad.asm') defsbad.asm:2: too many arguments for DEFS +>>> process_file('asmprepro.asm') +asmprepro.asm:8: warning: Recursive inclusion +asmprepro.asm:12: warning: Recursive inclusion +asmprepro.asm:12: warning: Recursive inclusion """ diff --git a/zxbasmpplex.py b/zxbasmpplex.py index b3f4fd5e0..456ac64e6 100755 --- a/zxbasmpplex.py +++ b/zxbasmpplex.py @@ -15,6 +15,7 @@ from ply import lex from api.config import OPTIONS import api.utils +import api.errmsg EOL = '\n' @@ -298,7 +299,7 @@ def include(self, filename): """ Changes FILENAME and line count """ if filename != STDIN and filename in [x[0] for x in self.filestack]: # Already included? - self.warning(filename + ' Recursive inclusion') + api.errmsg.warning(self.lex.lineno, ' Recursive inclusion') self.filestack.append([filename, 1, self.lex, self.input_data]) self.lex = lex.lex(object=self) @@ -407,11 +408,6 @@ def error(self, str): sys.exit(1) - def warning(self, str): - """ Emits a warning and continue execution. - """ - self.msg('Warning: %s' % str) - def __init__(self): """ Creates a new GLOBAL lexer instance """ From d0567209fe9dceb94c26e9e19e8347a7b0238496 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 5 Sep 2017 13:21:04 +0200 Subject: [PATCH 021/247] cleanup: fixed typo --- zxbasmpplex.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zxbasmpplex.py b/zxbasmpplex.py index 456ac64e6..870476330 100755 --- a/zxbasmpplex.py +++ b/zxbasmpplex.py @@ -419,7 +419,7 @@ def __init__(self): self.next_token = None # if set to something, this will be returned once -# --------------------- PREPROCESOR FUNCTIONS ------------------- +# --------------------- PREPROCESSOR FUNCTIONS ------------------- # Needed for states tmp = lex.lex(object=Lexer(), lextab='parsetab.zxbasmpplextab') From c926ed45e40845bc8119a2f48cfbd381b7baa0d4 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 5 Sep 2017 13:21:28 +0200 Subject: [PATCH 022/247] cleanup: uses str_ instead of str as var name --- zxbasmpplex.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zxbasmpplex.py b/zxbasmpplex.py index 870476330..f2df8f991 100755 --- a/zxbasmpplex.py +++ b/zxbasmpplex.py @@ -340,12 +340,12 @@ def include_end(self): return result - def input(self, str, filename=''): + def input(self, str_, filename=''): """ Defines input string, removing current lexer. """ self.filestack.append([filename, 1, self.lex, self.input_data]) - self.input_data = str + self.input_data = str_ self.lex = lex.lex(object=self) self.lex.input(self.input_data) From 49e356543e0208709abf16da96ed1533e0daa985 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 5 Sep 2017 13:22:13 +0200 Subject: [PATCH 023/247] cleanup: more elegant expression --- zxbasmpplex.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zxbasmpplex.py b/zxbasmpplex.py index f2df8f991..f7dc9750c 100755 --- a/zxbasmpplex.py +++ b/zxbasmpplex.py @@ -327,7 +327,7 @@ def include_end(self): self.input_data = self.filestack[-1][3] self.filestack.pop() - if self.filestack == []: # End of input? + if not self.filestack: # End of input? return self.filestack[-1][1] += 1 # Increment line counter of previous file From 11309df64e8b4aea7127bb1c11705c9abad1c88b Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 5 Sep 2017 15:20:53 +0200 Subject: [PATCH 024/247] correctly add include paths for zxb when testing --- tests/functional/test.py | 3 ++- zxbasmpplex.py | 24 ++++-------------------- 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/tests/functional/test.py b/tests/functional/test.py index b6e4c1315..e14192dd4 100755 --- a/tests/functional/test.py +++ b/tests/functional/test.py @@ -286,7 +286,8 @@ def testBAS(fname, filter_=None, inline=None): okfile = getName(fname) + os.extsep + ext if inline: - func = lambda: zxb.main(options + ['-I', ZXBASIC_ROOT]) + func = lambda: zxb.main(options + ['-I', ':'.join(os.path.join(ZXBASIC_ROOT, x) + for x in ('library', 'library-asm'))]) else: syscmd = '{0} {1}'.format(ZXB, ' '.join(options)) func = lambda: systemExec(syscmd) diff --git a/zxbasmpplex.py b/zxbasmpplex.py index f7dc9750c..52383268f 100755 --- a/zxbasmpplex.py +++ b/zxbasmpplex.py @@ -15,7 +15,7 @@ from ply import lex from api.config import OPTIONS import api.utils -import api.errmsg +from prepro.output import warning, error EOL = '\n' @@ -299,7 +299,7 @@ def include(self, filename): """ Changes FILENAME and line count """ if filename != STDIN and filename in [x[0] for x in self.filestack]: # Already included? - api.errmsg.warning(self.lex.lineno, ' Recursive inclusion') + warning(self.lex.lineno, ' Recursive inclusion') self.filestack.append([filename, 1, self.lex, self.input_data]) self.lex = lex.lex(object=self) @@ -313,11 +313,10 @@ def include(self, filename): if len(self.input_data) and self.input_data[-1] != EOL: self.input_data += EOL - - self.lex.input(self.input_data) except IOError: - self.error('cannot open "%s" file' % filename) + self.input_data = EOL + self.lex.input(self.input_data) return result def include_end(self): @@ -393,21 +392,6 @@ def find_column(self, token): return column - def msg(self, smsg): - """ Prints an error string msg. - """ - fname = os.path.basename(self.filestack[-1][0]) - line = self.lex.lineno - - OPTIONS.stderr.value.write('%s:%i %s\n' % (fname, line, smsg)) - - def error(self, str): - """ Prints an error msg, and exits. - """ - self.msg('Error: %s' % str) - - sys.exit(1) - def __init__(self): """ Creates a new GLOBAL lexer instance """ From 0836c3dc4c5d7b988d7c6b2ca06d8e9aa7c49fff Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 5 Sep 2017 15:23:31 +0200 Subject: [PATCH 025/247] do not exit on lexical error Usually the lexer will raise an exception. Now exits gracefully. This allows easier testing. --- zxbasmpplex.py | 21 +++++++++++++++++---- zxbpplex.py | 16 +++++++++------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/zxbasmpplex.py b/zxbasmpplex.py index 52383268f..756570207 100755 --- a/zxbasmpplex.py +++ b/zxbasmpplex.py @@ -13,7 +13,6 @@ import os import sys from ply import lex -from api.config import OPTIONS import api.utils from prepro.output import warning, error @@ -285,10 +284,14 @@ def t_prepro_FILENAME(self, t): t.value = t.value[1:-1] # Remove quotes return t + def t_defargs_defargsopt_prepro_define_defexpr_pragma_singlecomment_INITIAL_asmcomment_ANY(self, t): + r'.' + self.error("illegal preprocessor character '%s'" % t.value[0]) + def t_defargs_defargsopt_prepro_define_defexpr_pragma_singlecomment_INITIAL_asmcomment_error(self, t): - """ error handling rule + """ error handling rule. This should never happens! """ - self.error("illegal preprocessor character '%s'" % t.value[0]) + pass # The lexer will raise an exception here. This is intended def put_current_line(self, prefix=''): """ Returns line and file for include / end of include sequences. @@ -299,7 +302,7 @@ def include(self, filename): """ Changes FILENAME and line count """ if filename != STDIN and filename in [x[0] for x in self.filestack]: # Already included? - warning(self.lex.lineno, ' Recursive inclusion') + self.warning(' Recursive inclusion') self.filestack.append([filename, 1, self.lex, self.input_data]) self.lex = lex.lex(object=self) @@ -392,6 +395,16 @@ def find_column(self, token): return column + def error(self, msg): + """ Prints an error msg and continues execution. + """ + error(self.lex.lineno, msg) + + def warning(self, msg): + """ Emits a warning and continue execution. + """ + warning(self.lex.lineno, msg) + def __init__(self): """ Creates a new GLOBAL lexer instance """ diff --git a/zxbpplex.py b/zxbpplex.py index f2e017d4a..cdd79a630 100755 --- a/zxbpplex.py +++ b/zxbpplex.py @@ -353,11 +353,15 @@ def t_prepro_FILENAME(self, t): t.value = t.value[1:-1] # Remove quotes return t + def t_INITIAL_defargs_defargsopt_prepro_define_defexpr_pragma_comment_singlecomment_asm_asmcomment_if_ANY(self, t): + r'.' + self.error("illegal preprocessor character '%s'" % t.value[0]) + def t_INITIAL_defargs_defargsopt_prepro_define_defexpr_pragma_comment_singlecomment_asm_asmcomment_if_error(self, t): - """ error handling rule + """ error handling rule. Should never happen! """ - self.error("illegal preprocessor character '%s'" % t.value[0]) + pass # The lexer will raise an exception here. This is intended def put_current_line(self, prefix='', suffix=''): """ Returns line and file for include / end of include sequences. @@ -387,11 +391,10 @@ def include(self, filename): self.input_data = api.utils.read_txt_file(filename) if len(self.input_data) and self.input_data[-1] != EOL: self.input_data += EOL - - self.lex.input(self.input_data) except IOError: - self.error('cannot open "%s" file' % filename) + self.input_data = EOL + self.lex.input(self.input_data) return result def include_end(self): @@ -467,10 +470,9 @@ def find_column(self, token): return column def error(self, msg): - """ Prints an error msg, and exits. + """ Prints an error msg and continues execution. """ error(self.lex.lineno, msg) - sys.exit(1) def warning(self, msg): """ Emits a warning and continue execution. From 8a37f64eeb49eea72cb63cae7334e82b08fedc15 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 5 Sep 2017 15:25:28 +0200 Subject: [PATCH 026/247] preprocessor test added --- tests/functional/preprocerr1.asm | 2 ++ tests/functional/preprocerr2.asm | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 tests/functional/preprocerr1.asm create mode 100644 tests/functional/preprocerr2.asm diff --git a/tests/functional/preprocerr1.asm b/tests/functional/preprocerr1.asm new file mode 100644 index 000000000..cc839fee4 --- /dev/null +++ b/tests/functional/preprocerr1.asm @@ -0,0 +1,2 @@ +#include + diff --git a/tests/functional/preprocerr2.asm b/tests/functional/preprocerr2.asm new file mode 100644 index 000000000..1157a8e89 --- /dev/null +++ b/tests/functional/preprocerr2.asm @@ -0,0 +1,2 @@ +#define @ + From b21287e771e0e45e81a326ee399a2d2b74447049 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 5 Sep 2017 16:15:48 +0200 Subject: [PATCH 027/247] BASIC preproc test added --- tests/functional/baspreprocerr1.bas | 2 ++ tests/functional/baspreprocerr2.bas | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 tests/functional/baspreprocerr1.bas create mode 100644 tests/functional/baspreprocerr2.bas diff --git a/tests/functional/baspreprocerr1.bas b/tests/functional/baspreprocerr1.bas new file mode 100644 index 000000000..cc839fee4 --- /dev/null +++ b/tests/functional/baspreprocerr1.bas @@ -0,0 +1,2 @@ +#include + diff --git a/tests/functional/baspreprocerr2.bas b/tests/functional/baspreprocerr2.bas new file mode 100644 index 000000000..1157a8e89 --- /dev/null +++ b/tests/functional/baspreprocerr2.bas @@ -0,0 +1,2 @@ +#define @ + From 22d1b070d1f7940763859175f6a28a6c799b85dc Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 5 Sep 2017 16:14:49 +0200 Subject: [PATCH 028/247] bugfix: -e option parsed after zxbpp The -e options and others must be all parsed and set before invoking zxbpp or any other compiler module. --- zxb.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/zxb.py b/zxb.py index 8a3c7a747..1070e41db 100755 --- a/zxb.py +++ b/zxb.py @@ -214,10 +214,6 @@ def main(args=None): zxbpp.ID_TABLE.define('__CHECK_ARRAY_BOUNDARY__', lineno=0) OPTIONS.include_path.value = options.include_path - - zxbpp.setMode('basic') - zxbpp.main(args) - input_ = zxbpp.OUTPUT OPTIONS.inputFileName.value = zxbparser.FILENAME = \ os.path.basename(args[0]) @@ -229,9 +225,16 @@ def main(args=None): if OPTIONS.StdErrFileName.value: OPTIONS.stderr.value = open_file(OPTIONS.StdErrFileName.value, 'wt', 'utf-8') + zxbpp.setMode('basic') + zxbpp.main(args) + + if gl.has_errors: + debug.__DEBUG__("exiting due to errors.") + return 1 # Exit with errors + + input_ = zxbpp.OUTPUT zxbparser.parser.parse(input_, lexer=zxblex.lexer, tracking=True, debug=(OPTIONS.Debug.value > 2)) - if gl.has_errors: debug.__DEBUG__("exiting due to errors.") return 1 # Exit with errors From 8501bf8f6ddcee1f77551b1053e5e72b2f1a9b67 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 5 Sep 2017 19:05:37 +0200 Subject: [PATCH 029/247] update changelog --- ChangeLog | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 35c6f1665..4cd3e0dd8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,9 @@ ================================================================ Changes from Version 1.6.9 to 1.6.10 -* Added instructions ON .. GOTO and ON .. GOSUB -* Added UART library (by yomboprime) for serial communication -* Several bugfixes and minor errors ++ Added many more drawing primitives for Radastan Mode ++ Added instructions ON .. GOTO and ON .. GOSUB ++ Added UART library (by yomboprime) for serial communication +! Several bugfixes and minor errors and better stability * Better code generation * Allows array initialization with @label references * Switch .bas libraries (not the compiler) to MIT license From 1874932b63145d0c7b72661cb8c6817680c4a2c2 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 5 Sep 2017 19:41:18 +0200 Subject: [PATCH 030/247] added randplot.bas demo --- examples/randplot.bas | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 examples/randplot.bas diff --git a/examples/randplot.bas b/examples/randplot.bas new file mode 100644 index 000000000..c383efbce --- /dev/null +++ b/examples/randplot.bas @@ -0,0 +1,13 @@ + 1 REM ON .. GOTO usage example + 5 DIM x, y as Integer + 7 DIM s as UInteger +10 CLS: LET x=188: LET y=87: LET s=1: RANDOMIZE 1 +20 LET s=s+1: IF x>0 AND x<255 AND y>0 AND y<175 THEN PLOT x,y: PRINT AT 22,0;s:END IF +22 IF s=65535 THEN STOP:END IF +25 ON RND * 4 GOTO 30, 40, 50, 60 + +30 LET x=x+1: GO TO 20 +40 LET x=x-1: GO TO 20 +50 LET y=y+1: GO TO 20 +60 LET y=y-1: GO TO 20 + From 845cb674c6d4faaf943dbf815b786efa41f6cee6 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 5 Sep 2017 20:23:33 +0200 Subject: [PATCH 031/247] Add RadastanPrint routine Also add some comments. --- library/radastan.bas | 69 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 3 deletions(-) diff --git a/library/radastan.bas b/library/radastan.bas index fab39c4a4..bcd2d6030 100644 --- a/library/radastan.bas +++ b/library/radastan.bas @@ -488,6 +488,12 @@ SUB FASTCALL RadastanSetScreenAddr(ByVal scraddr as Uinteger) END SUB +' ---------------------------------------------------------------- +' Sub RadastanPrintChar +' +' Prints the current character (ASCII Code) at the current +' cursor position. The cursor is updated. +' ---------------------------------------------------------------- SUB FASTCALL RadastanPrintChar(ByVal char as UByte) ASM PROC @@ -592,8 +598,6 @@ __RADASTAN_NEXT_PRN_POS: ld a, 6 jp _RadastanScrollUp -__RADASTAN_PRN_POS: - dw 0 ENDP END ASM DIM dummy as Uinteger @@ -601,6 +605,65 @@ __RADASTAN_PRN_POS: END SUB +' ---------------------------------------------------------------- +' SUB RadastanPrint +' +' Prints the given string in radastan mode. Allows chr$(13) as +' newline and chr$(10) as return +' ---------------------------------------------------------------- +SUB RadastanPrint(ByVal s as String) + DIM dummy as Uinteger + dummy = @RadastanPrintChar + ASM + PROC + LOCAL loop, next_char, no_newline, no_line_return, finish + ld l, (ix + 4) + ld h, (ix + 5) + ld c, (hl) + inc hl + ld b, (hl) + ld a, b + or c + jr z, finish + ld a, c + ld c, b + ld b, a + inc c + +loop: + inc hl + ld a, (hl) + cp 13 + jr nz, no_newline + xor a + exx + call __RADASTAN_NEXT_PRN_POS + exx + jp next_char + +no_newline: + cp 10 + jr nz, no_line_return + xor a + ld (_RadastanColRow), a + jp next_char + +no_line_return: + exx + call _RadastanPrintChar + exx + +next_char: + djnz loop + dec c + jp nz, loop + +finish: + ENDP + END ASM +END SUB + + ' ---------------------------------------------------------------- ' Sub RadastanHaploFont ' @@ -623,7 +686,7 @@ END SUB SUB FASTCALL RadastanPrintNL() ASM xor a - jp __RADASTAN_MOVE_CURSOR + jp __RADASTAN_NEXT_PRN_POS: END ASM END SUB From 9a5cb18142ce28f323b4165f946b8affc138a6a8 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 5 Sep 2017 20:25:51 +0200 Subject: [PATCH 032/247] =?UTF-8?q?Bump=20version:=201.6.9=20=E2=86=92=201?= =?UTF-8?q?.6.10?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index f21ee42a7..ae7f5085e 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,4 +1,4 @@ [bumpversion] -current_version = 1.6.9 +current_version = 1.6.10 files = version.py diff --git a/version.py b/version.py index d50440bd9..1fb655acd 100755 --- a/version.py +++ b/version.py @@ -1 +1 @@ -VERSION = '1.6.9' +VERSION = '1.6.10' From c7ce9dce9baf4f64f3d8ce35263470d0dde017e5 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 6 Sep 2017 11:14:02 +0200 Subject: [PATCH 033/247] make #line directives to report path --- tests/functional/prepro00.out | 2 +- tests/functional/prepro01.out | 2 +- tests/functional/prepro30.out | 2 +- tests/functional/prepro70.out | 2 +- tests/functional/prepro71.bi | 4 + tests/functional/prepro71.out | 204 ++++++++++++++++++++++++++++++++++ tests/functional/prepro72.bi | 9 ++ tests/functional/prepro72.out | 13 +++ zxbpp.py | 5 + zxbpplex.py | 3 +- 10 files changed, 240 insertions(+), 6 deletions(-) create mode 100644 tests/functional/prepro71.bi create mode 100644 tests/functional/prepro71.out create mode 100644 tests/functional/prepro72.bi create mode 100644 tests/functional/prepro72.out diff --git a/tests/functional/prepro00.out b/tests/functional/prepro00.out index be9dadcd4..8c3dc2129 100644 --- a/tests/functional/prepro00.out +++ b/tests/functional/prepro00.out @@ -1,5 +1,5 @@ #line 1 "prepro00.bi" -#line 1 "attr.bas" +#line 1 "/src/zxb/trunk/library/attr.bas" diff --git a/tests/functional/prepro01.out b/tests/functional/prepro01.out index 9bd51eb09..b4e23e1ea 100644 --- a/tests/functional/prepro01.out +++ b/tests/functional/prepro01.out @@ -1,5 +1,5 @@ #line 1 "prepro01.bi" -#line 1 "attr.bas" +#line 1 "/src/zxb/trunk/library/attr.bas" diff --git a/tests/functional/prepro30.out b/tests/functional/prepro30.out index 7ad765a73..61bcc3a1b 100644 --- a/tests/functional/prepro30.out +++ b/tests/functional/prepro30.out @@ -1,5 +1,5 @@ #line 1 "prepro30.bi" -#line 1 "attr.bas" +#line 1 "/src/zxb/trunk/library/attr.bas" diff --git a/tests/functional/prepro70.out b/tests/functional/prepro70.out index cdae4ec69..599230c43 100644 --- a/tests/functional/prepro70.out +++ b/tests/functional/prepro70.out @@ -3,7 +3,7 @@ DIM b -#line 1 "prepro70.bi" +#line 1 "./prepro70.bi" DIM b #line 10 "./prepro70.bi" #line 6 "prepro70.bi" diff --git a/tests/functional/prepro71.bi b/tests/functional/prepro71.bi new file mode 100644 index 000000000..aece9dbd6 --- /dev/null +++ b/tests/functional/prepro71.bi @@ -0,0 +1,4 @@ +#include "alloc.bas" + +PRINT "HOLA" + diff --git a/tests/functional/prepro71.out b/tests/functional/prepro71.out new file mode 100644 index 000000000..cd20bf26d --- /dev/null +++ b/tests/functional/prepro71.out @@ -0,0 +1,204 @@ +#line 1 "prepro71.bi" +#line 1 "/src/zxb/trunk/library/alloc.bas" + + + + + + + + + + + + + +#pragma push(case_insensitive) +#pragma case_insensitive = True + + + + + + + + + + + + + + + +function FASTCALL allocate(byval n as uinteger) as uinteger + + + + + asm + ld b, h + ld c, l + jp __MEM_ALLOC + end asm +end function + + + + + + + + +sub FASTCALL deallocate(byval addr as integer) + + + + asm + jp __MEM_FREE + end asm +end sub + + + + + + + + + + + + + + + + +function FASTCALL reallocate(byval addr as uinteger, byval n as uinteger) as uinteger + + + + + + asm + ex de, hl + pop hl + ex (sp), hl + ld b, h + ld c, l + ex de, hl + jp __REALLOC + end asm +end function + + + + + + + + +function FASTCALL memavail as uInteger + asm + PROC + + LOCAL LOOP + + ld hl, ZXBASIC_MEM_HEAP + ld de, 0 + +LOOP: + + ld c, (hl) + inc hl + ld b, (hl) + inc hl + + + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + + + ex de, hl + add hl, bc + ex de, hl + + + ld a, h + or l + jr nz, LOOP + + ex de, hl + + ENDP + end asm +end function + + + + + + + +function FASTCALL maxavail as uInteger + asm + PROC + + LOCAL LOOP, CONT + + ld hl, ZXBASIC_MEM_HEAP + ld de, 0 + +LOOP: + + ld c, (hl) + inc hl + ld b, (hl) + inc hl + + + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + + + + ex de, hl + or a + sbc hl, bc + add hl, bc + ex de, hl + + + jr nc, CONT + + ld d, b + ld e, c + +CONT: + + ld a, h + or l + jr nz, LOOP + + ex de, hl + + ENDP + end asm +end function + + +#pragma pop(case_insensitive) + +#require "alloc.asm" +#require "free.asm" +#require "realloc.asm" + +#line 198 "/src/zxb/trunk/library/alloc.bas" + +#line 2 "prepro71.bi" + +PRINT "HOLA" + diff --git a/tests/functional/prepro72.bi b/tests/functional/prepro72.bi new file mode 100644 index 000000000..45d7a8984 --- /dev/null +++ b/tests/functional/prepro72.bi @@ -0,0 +1,9 @@ +DIM b +#ifndef __INCLUDED__ +#define __INCLUDED__ + +#include "./prepro70.bi" + +DIM a + +#endif diff --git a/tests/functional/prepro72.out b/tests/functional/prepro72.out new file mode 100644 index 000000000..3ba0b5f2a --- /dev/null +++ b/tests/functional/prepro72.out @@ -0,0 +1,13 @@ +#line 1 "prepro72.bi" +DIM b + + + +#line 1 "./prepro70.bi" +DIM b +#line 10 "./prepro70.bi" +#line 6 "prepro72.bi" + +DIM a + +#line 10 "prepro72.bi" diff --git a/zxbpp.py b/zxbpp.py index 433a31ef0..da4f38a0a 100755 --- a/zxbpp.py +++ b/zxbpp.py @@ -714,11 +714,16 @@ def filter_(input_, filename='', state='INITIAL'): """ Filter the input string thought the preprocessor. result is appended to OUTPUT global str """ + global CURRENT_DIR + + prev_dir = CURRENT_DIR CURRENT_FILE.append(filename) + CURRENT_DIR = os.path.dirname(CURRENT_FILE[-1]) LEXER.input(input_, filename) LEXER.lex.begin(state) parser.parse(lexer=LEXER, debug=OPTIONS.Debug.value > 2) CURRENT_FILE.pop() + CURRENT_DIR = prev_dir def main(argv): diff --git a/zxbpplex.py b/zxbpplex.py index cdd79a630..65dd81b1c 100755 --- a/zxbpplex.py +++ b/zxbpplex.py @@ -10,7 +10,6 @@ # This is the Lexer for the ZXBpp (ZXBasic Preprocessor) # ---------------------------------------------------------------------- -import os import sys from ply import lex from prepro.output import warning, error @@ -366,7 +365,7 @@ def t_INITIAL_defargs_defargsopt_prepro_define_defexpr_pragma_comment_singlecomm def put_current_line(self, prefix='', suffix=''): """ Returns line and file for include / end of include sequences. """ - return '%s#line %i "%s"%s' % (prefix, self.lex.lineno, os.path.basename(self.filestack[-1][0]), suffix) + return '%s#line %i "%s"%s' % (prefix, self.lex.lineno, self.filestack[-1][0], suffix) def include(self, filename): """ Changes FILENAME and line count From 928b40c48eca3742385f1b5367b83528153ac877 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Thu, 7 Sep 2017 00:24:46 +0200 Subject: [PATCH 034/247] bugfix: fix include files with < > Sometimes you could not use include " "... after a include with brackets < >. Fixed. --- tests/functional/prepro73.bi | 7 ++++ tests/functional/prepro73.out | 69 +++++++++++++++++++++++++++++++++++ zxbpp.py | 6 ++- 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 tests/functional/prepro73.bi create mode 100644 tests/functional/prepro73.out diff --git a/tests/functional/prepro73.bi b/tests/functional/prepro73.bi new file mode 100644 index 000000000..8a9862324 --- /dev/null +++ b/tests/functional/prepro73.bi @@ -0,0 +1,7 @@ +#include + +#ifndef __D7_BAS__ +#define __D7_BAS__ +#include "prepro73.bi" +#endif + diff --git a/tests/functional/prepro73.out b/tests/functional/prepro73.out new file mode 100644 index 000000000..802529748 --- /dev/null +++ b/tests/functional/prepro73.out @@ -0,0 +1,69 @@ +#line 1 "prepro73.bi" +#line 1 "/src/zxb/trunk/library/pos.bas" + + + + + + + + + + + + + + + +#pragma push(case_insensitive) +#pragma case_insensitive = true + + + + + + + + + +function FASTCALL pos as ubyte + asm + PROC + + call __LOAD_S_POSN + ld a, e + + ENDP + end asm +end function + +#pragma pop(case_insensitive) +#require "sposn.asm" + + +#line 43 "/src/zxb/trunk/library/pos.bas" + +#line 2 "prepro73.bi" + + + +#line 1 "prepro73.bi" +#line 1 "/src/zxb/trunk/library/pos.bas" + + + + + + + + + +#line 43 "/src/zxb/trunk/library/pos.bas" + +#line 2 "prepro73.bi" + +#line 7 "prepro73.bi" + +#line 6 "prepro73.bi" +#line 7 "prepro73.bi" + diff --git a/zxbpp.py b/zxbpp.py index da4f38a0a..858a95aca 100755 --- a/zxbpp.py +++ b/zxbpp.py @@ -124,7 +124,7 @@ def search_filename(fname, lineno, local_first): the file being analyzed. """ fname = sanitize_file(fname) - i_path = [CURRENT_DIR] + INCLUDEPATH if local_first else INCLUDEPATH + i_path = [CURRENT_DIR] + INCLUDEPATH if local_first else list(INCLUDEPATH) i_path.extend(OPTIONS.include_path.value.split(':') if OPTIONS.include_path.value else []) if os.path.isabs(fname): if os.path.isfile(fname): @@ -271,8 +271,10 @@ def p_token(p): def p_include_file(p): """ include_file : include NEWLINE program _ENDFILE_ """ + global CURRENT_DIR p[0] = [p[1] + p[2]] + p[3] + [p[4]] CURRENT_FILE.pop() # Remove top of the stack + CURRENT_DIR = os.path.dirname(CURRENT_FILE[-1]) def p_include_file_empty(p): @@ -290,8 +292,10 @@ def p_include_once_empty(p): def p_include_once_ok(p): """ include_file : include_once NEWLINE program _ENDFILE_ """ + global CURRENT_DIR p[0] = [p[1]] + p[3] + [p[4]] CURRENT_FILE.pop() # Remove top of the stack + CURRENT_DIR = os.path.dirname(CURRENT_FILE[-1]) def p_include(p): From 673ead48f79c216eb6503daebac78a80e83c7293 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 5 Sep 2017 21:01:49 +0200 Subject: [PATCH 035/247] remove README.md and LICENSE.txt from installation --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index fd2509511..d4c827998 100644 --- a/setup.py +++ b/setup.py @@ -34,7 +34,7 @@ def get_files(folder): url='https://bitbucket.org/boriel/zxbasic', download_url='http://boriel.com/files/zxb/zxbasic-%s.tar.gz' % version.VERSION, keywords=['compiler', 'zxspectrum', 'BASIC', 'z80'], # arbitrary keywords - data_files=[(os.path.join('bin', x), get_files(x)) for x in file_dirs] + ['README.md', 'LICENSE.txt'], + data_files=[(os.path.join('bin', x), get_files(x)) for x in file_dirs], license='GPL3', entry_points={ 'console_scripts': [ From 3ef6e428d6e91968050c72854bc1c44677e06634 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 6 Sep 2017 23:27:42 +0200 Subject: [PATCH 036/247] add missing changelog --- ChangeLog | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ChangeLog b/ChangeLog index 4cd3e0dd8..cc644c5dc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -58,6 +58,19 @@ and attribute traversal which depends on the symbolTYPE being parsed. e.g. for symbolBINARY (binary expressions), we have node.left, node.right, node.operand, but also node.children[0], node.children[1]. +===From Version 1.2.9 to 1.3.0=== +* ! Fixed a bug in USR +* ! Fixed a bug in SAVE / LOAD +* ! Fixed a serious bug in the preprocessor +* ! Fixed a bug with DIM and constants +* ! Fixed a bug with SHL/SHR for 0 shifts +* + Added -D option. ZXBASIC now allows commandline macro definition +* ! Fixed a bug with CODE and INKEY$ +* ! Fixed a bug with string slicing assignation (e.g. a$(3) = "x") +* ! Fixed a bug with arrays of integer assignation (e.g. a(3) = 5, being a of Integer type) +* ! Fixed a bug with peephole optimizer (-O3) +* * Some changes and code refactorization towards 2.x branch + ================================================================ Changes from Version 1.2.8 to 1.2.9 From f3b7873c92c16f1d27838334eda15e7055f5ec8d Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 6 Sep 2017 12:48:04 +0200 Subject: [PATCH 037/247] optimize memcopy --- library-asm/memcopy.asm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library-asm/memcopy.asm b/library-asm/memcopy.asm index 24b1f45de..19429ebf5 100644 --- a/library-asm/memcopy.asm +++ b/library-asm/memcopy.asm @@ -19,11 +19,10 @@ __MEMCPY: PROC LOCAL __MEMCPY2 - push hl add hl, bc or a sbc hl, de ; checks if DE > HL + BC - pop hl ; recovers HL. If Carry set => DE > HL + add hl, de ; recovers HL. If Carry set => DE > HL jr c, __MEMCPY2 ; Now checks if DE <= HL @@ -45,5 +44,5 @@ __MEMCPY: __MEMCPY2: ldir ret - + ENDP From 5477351b7a31043a451d215863a6a96a360a4bfd Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 6 Sep 2017 13:00:26 +0200 Subject: [PATCH 038/247] remove unneeded dependency --- library-asm/random.asm | 2 - tests/functional/mcleod.asm | 92 ---------------------------------- tests/functional/randomize.asm | 92 ---------------------------------- 3 files changed, 186 deletions(-) diff --git a/library-asm/random.asm b/library-asm/random.asm index 958d5f9a3..03d01e1de 100644 --- a/library-asm/random.asm +++ b/library-asm/random.asm @@ -1,7 +1,5 @@ ; RANDOM functions -#include once - RANDOMIZE: ; Randomize with 32 bit seed in DE HL ; if SEED = 0, calls ROM to take frames as seed diff --git a/tests/functional/mcleod.asm b/tests/functional/mcleod.asm index 3c12ac614..7e4bc568c 100644 --- a/tests/functional/mcleod.asm +++ b/tests/functional/mcleod.asm @@ -218,98 +218,6 @@ __MULF: ; Multiplication #line 1 "random.asm" ; RANDOM functions -#line 1 "mul32.asm" -#line 1 "_mul32.asm" - -; Ripped from: http://www.andreadrian.de/oldcpu/z80_number_cruncher.html#moztocid784223 - ; Used with permission. - ; Multiplies 32x32 bit integer (DEHL x D'E'H'L') - ; 64bit result is returned in H'L'H L B'C'A C - - -__MUL32_64START: - push hl - exx - ld b, h - ld c, l ; BC = Low Part (A) - pop hl ; HL = Load Part (B) - ex de, hl ; DE = Low Part (B), HL = HightPart(A) (must be in B'C') - push hl - - exx - pop bc ; B'C' = HightPart(A) - exx ; A = B'C'BC , B = D'E'DE - - ; multiply routine 32 * 32bit = 64bit - ; h'l'hlb'c'ac = b'c'bc * d'e'de - ; needs register a, changes flags - ; - ; this routine was with tiny differences in the - ; sinclair zx81 rom for the mantissa multiply - -__LMUL: - and a ; reset carry flag - sbc hl,hl ; result bits 32..47 = 0 - exx - sbc hl,hl ; result bits 48..63 = 0 - exx - ld a,b ; mpr is b'c'ac - ld b,33 ; initialize loop counter - jp __LMULSTART - -__LMULLOOP: - jr nc,__LMULNOADD ; JP is 2 cycles faster than JR. Since it's inside a LOOP - ; it can save up to 33 * 2 = 66 cycles - ; But JR if 3 cycles faster if JUMP not taken! - add hl,de ; result += mpd - exx - adc hl,de - exx - -__LMULNOADD: - exx - rr h ; right shift upper - rr l ; 32bit of result - exx - rr h - rr l - -__LMULSTART: - exx - rr b ; right shift mpr/ - rr c ; lower 32bit of result - exx - rra ; equivalent to rr a - rr c - djnz __LMULLOOP - - ret ; result in h'l'hlb'c'ac - -#line 2 "mul32.asm" - -__MUL32: ; multiplies 32 bit un/signed integer. - ; First operand stored in DEHL, and 2nd onto stack - ; Lowest part of 2nd operand on top of the stack - ; returns the result in DE.HL - exx - pop hl ; Return ADDRESS - pop de ; Low part - ex (sp), hl ; CALLEE -> HL = High part - ex de, hl - call __MUL32_64START - -__TO32BIT: ; Converts H'L'HLB'C'AC to DEHL (Discards H'L'HL) - exx - push bc - exx - pop de - ld h, a - ld l, c - ret - - -#line 4 "random.asm" - RANDOMIZE: ; Randomize with 32 bit seed in DE HL ; if SEED = 0, calls ROM to take frames as seed diff --git a/tests/functional/randomize.asm b/tests/functional/randomize.asm index a6ff7ae9e..dd64c634f 100644 --- a/tests/functional/randomize.asm +++ b/tests/functional/randomize.asm @@ -35,98 +35,6 @@ __CALL_BACK__: #line 1 "random.asm" ; RANDOM functions -#line 1 "mul32.asm" -#line 1 "_mul32.asm" - -; Ripped from: http://www.andreadrian.de/oldcpu/z80_number_cruncher.html#moztocid784223 - ; Used with permission. - ; Multiplies 32x32 bit integer (DEHL x D'E'H'L') - ; 64bit result is returned in H'L'H L B'C'A C - - -__MUL32_64START: - push hl - exx - ld b, h - ld c, l ; BC = Low Part (A) - pop hl ; HL = Load Part (B) - ex de, hl ; DE = Low Part (B), HL = HightPart(A) (must be in B'C') - push hl - - exx - pop bc ; B'C' = HightPart(A) - exx ; A = B'C'BC , B = D'E'DE - - ; multiply routine 32 * 32bit = 64bit - ; h'l'hlb'c'ac = b'c'bc * d'e'de - ; needs register a, changes flags - ; - ; this routine was with tiny differences in the - ; sinclair zx81 rom for the mantissa multiply - -__LMUL: - and a ; reset carry flag - sbc hl,hl ; result bits 32..47 = 0 - exx - sbc hl,hl ; result bits 48..63 = 0 - exx - ld a,b ; mpr is b'c'ac - ld b,33 ; initialize loop counter - jp __LMULSTART - -__LMULLOOP: - jr nc,__LMULNOADD ; JP is 2 cycles faster than JR. Since it's inside a LOOP - ; it can save up to 33 * 2 = 66 cycles - ; But JR if 3 cycles faster if JUMP not taken! - add hl,de ; result += mpd - exx - adc hl,de - exx - -__LMULNOADD: - exx - rr h ; right shift upper - rr l ; 32bit of result - exx - rr h - rr l - -__LMULSTART: - exx - rr b ; right shift mpr/ - rr c ; lower 32bit of result - exx - rra ; equivalent to rr a - rr c - djnz __LMULLOOP - - ret ; result in h'l'hlb'c'ac - -#line 2 "mul32.asm" - -__MUL32: ; multiplies 32 bit un/signed integer. - ; First operand stored in DEHL, and 2nd onto stack - ; Lowest part of 2nd operand on top of the stack - ; returns the result in DE.HL - exx - pop hl ; Return ADDRESS - pop de ; Low part - ex (sp), hl ; CALLEE -> HL = High part - ex de, hl - call __MUL32_64START - -__TO32BIT: ; Converts H'L'HLB'C'AC to DEHL (Discards H'L'HL) - exx - push bc - exx - pop de - ld h, a - ld l, c - ret - - -#line 4 "random.asm" - RANDOMIZE: ; Randomize with 32 bit seed in DE HL ; if SEED = 0, calls ROM to take frames as seed From ba20470c697f92fbc9caaaf32f2aae4967ccb135 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Thu, 7 Sep 2017 21:40:25 +0200 Subject: [PATCH 039/247] bugfix: fix path include problems in win32 Fixes the bug of infinite "Recursive Inclusion" in win32 --- ChangeLog | 5 +++++ zxbpp.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index cc644c5dc..e8bfdfafe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,9 @@ ================================================================ +Changes from Version 1.6.10 to 1.6.11 +! Fix infinite recursive include in Windows (yes, win sucks) +* Little optimizations in memset and rnd +* Standarize file includes like in cpp +================================================================ Changes from Version 1.6.9 to 1.6.10 + Added many more drawing primitives for Radastan Mode + Added instructions ON .. GOTO and ON .. GOSUB diff --git a/zxbpp.py b/zxbpp.py index 858a95aca..db744b714 100755 --- a/zxbpp.py +++ b/zxbpp.py @@ -131,7 +131,7 @@ def search_filename(fname, lineno, local_first): return fname else: for dir_ in i_path: - path = os.path.join(dir_, fname) + path = sanitize_file(os.path.join(dir_, fname)) if os.path.exists(path): return path From d357a0c23cef077e9c7b4ee2373f5c751e471247 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Thu, 7 Sep 2017 21:47:05 +0200 Subject: [PATCH 040/247] =?UTF-8?q?Bump=20version:=201.6.10=20=E2=86=92=20?= =?UTF-8?q?1.6.11?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index ae7f5085e..56d09473d 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,4 +1,4 @@ [bumpversion] -current_version = 1.6.10 +current_version = 1.6.11 files = version.py diff --git a/version.py b/version.py index 1fb655acd..d956d4c2d 100755 --- a/version.py +++ b/version.py @@ -1 +1 @@ -VERSION = '1.6.10' +VERSION = '1.6.11' From 42238f471bf9b28352a46db51f37eafc93a0ff38 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 8 Sep 2017 11:03:01 +0200 Subject: [PATCH 041/247] bugfix: binary test where not being updated When using test.py -U on binary tests these where not being updated. Fixed. --- tests/functional/test.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/functional/test.py b/tests/functional/test.py index e14192dd4..eb3515c3c 100755 --- a/tests/functional/test.py +++ b/tests/functional/test.py @@ -206,7 +206,10 @@ def _get_testbas_options(fname): match = reBIN.match(getName(fname)) if match and match.groups()[0].lower() in ('tzx', 'tap'): ext = match.groups()[0].lower() - tfname = os.path.join(TEMP_DIR, getName(fname) + os.extsep + ext) + if not UPDATE: + tfname = os.path.join(TEMP_DIR, getName(fname) + os.extsep + ext) + else: + tfname = getName(fname) + os.extsep + ext options.extend(['--%s' % ext, fname, '-o', tfname] + prep) else: ext = 'asm' From fe56450f9fe1282ce7a3d6fda2ccd7d7eac58792 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 8 Sep 2017 11:42:51 +0200 Subject: [PATCH 042/247] correctly updates preproc paths File paths and others, for testing, should be relative to the _origina_root variable defined in test.py --- tests/functional/test.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/functional/test.py b/tests/functional/test.py index eb3515c3c..3cd6313b8 100755 --- a/tests/functional/test.py +++ b/tests/functional/test.py @@ -242,6 +242,11 @@ def testPREPRO(fname, pattern_=None): if not UPDATE and not err_lvl: result = is_same_file(okfile, tfname, replace_regexp=pattern_, replace_what=ZXBASIC_ROOT, replace_with=_original_root) + else: + lines = get_file_lines(tfname, replace_regexp=pattern_, replace_what=ZXBASIC_ROOT, + replace_with=_original_root) + with zxb.api.utils.open_file(tfname, 'wt', encoding='utf-8') as f: + f.write(''.join(lines)) return result @@ -299,6 +304,11 @@ def testBAS(fname, filter_=None, inline=None): with TempTestFile(func, tfname, UPDATE): if not UPDATE: result = is_same_file(okfile, tfname, filter_, is_binary=reBIN.match(fname) is not None) + else: + lines = get_file_lines(tfname, replace_regexp=FILTER, replace_what=ZXBASIC_ROOT, + replace_with=_original_root) + with zxb.api.utils.open_file(tfname, 'wt', encoding='utf-8') as f: + f.write(''.join(lines)) return result From e5caed463522265dfaa44bac74aceca7fa4fa4e5 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 8 Sep 2017 12:18:52 +0200 Subject: [PATCH 043/247] correctly update not existing tests --- tests/functional/test.py | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/tests/functional/test.py b/tests/functional/test.py index 3cd6313b8..b09e33775 100755 --- a/tests/functional/test.py +++ b/tests/functional/test.py @@ -222,6 +222,16 @@ def _get_testbas_options(fname): return options, tfname, ext +def updateTest(tfname, pattern_): + if not os.path.exists(tfname): + return # was deleted -> The test is an error test and no compile filed should exist + + lines = get_file_lines(tfname, replace_regexp=pattern_, replace_what=ZXBASIC_ROOT, + replace_with=_original_root) + with zxb.api.utils.open_file(tfname, 'wt', encoding='utf-8') as f: + f.write(''.join(lines)) + + def testPREPRO(fname, pattern_=None): global UPDATE @@ -235,6 +245,8 @@ def testPREPRO(fname, pattern_=None): if UPDATE: tfname = okfile + if os.path.exists(okfile): + os.unlink(okfile) syscmd = '{0} {1} {2} > {3}{4}'.format(ZXBPP, OPTIONS, fname, tfname, prep) result = None @@ -243,10 +255,7 @@ def testPREPRO(fname, pattern_=None): result = is_same_file(okfile, tfname, replace_regexp=pattern_, replace_what=ZXBASIC_ROOT, replace_with=_original_root) else: - lines = get_file_lines(tfname, replace_regexp=pattern_, replace_what=ZXBASIC_ROOT, - replace_with=_original_root) - with zxb.api.utils.open_file(tfname, 'wt', encoding='utf-8') as f: - f.write(''.join(lines)) + updateTest(tfname, pattern_) return result @@ -260,6 +269,8 @@ def testASM(fname, inline=None): if UPDATE: tfname = okfile + if os.path.exists(okfile): + os.unlink(okfile) options = [fname, '-o', tfname] + prep @@ -293,6 +304,9 @@ def testBAS(fname, filter_=None, inline=None): options, tfname, ext = _get_testbas_options(fname) okfile = getName(fname) + os.extsep + ext + if UPDATE and os.path.exists(okfile): + os.unlink(okfile) + if inline: func = lambda: zxb.main(options + ['-I', ':'.join(os.path.join(ZXBASIC_ROOT, x) for x in ('library', 'library-asm'))]) @@ -305,10 +319,7 @@ def testBAS(fname, filter_=None, inline=None): if not UPDATE: result = is_same_file(okfile, tfname, filter_, is_binary=reBIN.match(fname) is not None) else: - lines = get_file_lines(tfname, replace_regexp=FILTER, replace_what=ZXBASIC_ROOT, - replace_with=_original_root) - with zxb.api.utils.open_file(tfname, 'wt', encoding='utf-8') as f: - f.write(''.join(lines)) + updateTest(tfname, FILTER) return result From 0b3adfc8acbacd10fcbe7667edefa21e017db9f9 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 8 Sep 2017 00:33:01 +0200 Subject: [PATCH 044/247] bugfix: missing new line after #include once --- tests/functional/prepro30.out | 1 + tests/functional/prepro74.bi | 9 ++++++ tests/functional/prepro74.out | 61 +++++++++++++++++++++++++++++++++++ tests/functional/prepro75.bi | 6 ++++ tests/functional/prepro75.out | 11 +++++++ zxbpp.py | 2 +- 6 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 tests/functional/prepro74.bi create mode 100644 tests/functional/prepro74.out create mode 100644 tests/functional/prepro75.bi create mode 100644 tests/functional/prepro75.out diff --git a/tests/functional/prepro30.out b/tests/functional/prepro30.out index 61bcc3a1b..9bb0ba74e 100644 --- a/tests/functional/prepro30.out +++ b/tests/functional/prepro30.out @@ -12,6 +12,7 @@ + #pragma push(case_insensitive) #pragma case_insensitive = TRUE diff --git a/tests/functional/prepro74.bi b/tests/functional/prepro74.bi new file mode 100644 index 000000000..6e9f255d3 --- /dev/null +++ b/tests/functional/prepro74.bi @@ -0,0 +1,9 @@ +#include once + +#ifndef __D7_BAS__ +#define __D7_BAS__ +#include "prepro74.bi" +#endif + +glibberish + diff --git a/tests/functional/prepro74.out b/tests/functional/prepro74.out new file mode 100644 index 000000000..5c67a4d1e --- /dev/null +++ b/tests/functional/prepro74.out @@ -0,0 +1,61 @@ +#line 1 "prepro74.bi" +#line 1 "/src/zxb/trunk/library/pos.bas" + + + + + + + + + + + + + + + +#pragma push(case_insensitive) +#pragma case_insensitive = true + + + + + + + + + +function FASTCALL pos as ubyte + asm + PROC + + call __LOAD_S_POSN + ld a, e + + ENDP + end asm +end function + +#pragma pop(case_insensitive) +#require "sposn.asm" + + +#line 43 "/src/zxb/trunk/library/pos.bas" + +#line 2 "prepro74.bi" + + + +#line 1 "prepro74.bi" + + +#line 7 "prepro74.bi" + +glibberish + +#line 6 "prepro74.bi" +#line 7 "prepro74.bi" + +glibberish + diff --git a/tests/functional/prepro75.bi b/tests/functional/prepro75.bi new file mode 100644 index 000000000..e55313467 --- /dev/null +++ b/tests/functional/prepro75.bi @@ -0,0 +1,6 @@ +A = 0 +#ifndef __TEST__ +#define __TEST__ +#include once "prepro75.bi" +#endif + diff --git a/tests/functional/prepro75.out b/tests/functional/prepro75.out new file mode 100644 index 000000000..cb2ba7e75 --- /dev/null +++ b/tests/functional/prepro75.out @@ -0,0 +1,11 @@ +#line 1 "prepro75.bi" +A = 0 + + +#line 1 "prepro75.bi" +A = 0 +#line 6 "prepro75.bi" + +#line 5 "prepro75.bi" +#line 6 "prepro75.bi" + diff --git a/zxbpp.py b/zxbpp.py index db744b714..aba611500 100755 --- a/zxbpp.py +++ b/zxbpp.py @@ -293,7 +293,7 @@ def p_include_once_ok(p): """ include_file : include_once NEWLINE program _ENDFILE_ """ global CURRENT_DIR - p[0] = [p[1]] + p[3] + [p[4]] + p[0] = [p[1] + p[2]] + p[3] + [p[4]] CURRENT_FILE.pop() # Remove top of the stack CURRENT_DIR = os.path.dirname(CURRENT_FILE[-1]) From c8f6db1ad39b17de6a7902978f3a8aeb2cf85027 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 8 Sep 2017 12:46:59 +0200 Subject: [PATCH 045/247] update BASIC tests to reflect new paths --- tests/functional/19.asm | 11 ++++++++ tests/functional/21.asm | 1 + tests/functional/25.asm | 1 + tests/functional/27.asm | 11 ++++++-- tests/functional/28.asm | 12 ++++++-- tests/functional/29.asm | 13 +++++++-- tests/functional/31.asm | 4 +++ tests/functional/34.asm | 2 ++ tests/functional/35.asm | 6 ++++ tests/functional/36.asm | 6 ++++ tests/functional/37.asm | 6 ++++ tests/functional/38.asm | 6 ++++ tests/functional/39.asm | 2 ++ tests/functional/40.asm | 2 ++ tests/functional/43.asm | 2 ++ tests/functional/46.asm | 16 ++++++----- tests/functional/47.asm | 16 ++++++----- tests/functional/48.asm | 14 ++++++++-- tests/functional/49.asm | 14 ++++++++-- tests/functional/55.asm | 16 ++++++----- tests/functional/abs32.asm | 2 ++ tests/functional/addstr.asm | 11 ++++++-- tests/functional/aloadstr0.asm | 10 +++++-- tests/functional/aloadstr1.asm | 26 ++++++++++++------ tests/functional/and16.asm | 1 + tests/functional/and32.asm | 1 + tests/functional/and8.asm | 1 + tests/functional/arden2.asm | 12 ++++++-- tests/functional/array03.asm | 16 ++++++----- tests/functional/array06.asm | 16 ++++++----- tests/functional/array07.asm | 27 ++++++++++++------ tests/functional/array09.asm | 27 ++++++++++++------ tests/functional/array10.asm | 16 ++++++----- tests/functional/astore16.asm | 42 ++++++++++++++++++++++------ tests/functional/atlabel1.asm | 1 + tests/functional/attr.asm | 13 +++++++-- tests/functional/band16.asm | 1 + tests/functional/band32.asm | 1 + tests/functional/band8.asm | 1 + tests/functional/bitwise.asm | 1 + tests/functional/bnot16.asm | 1 + tests/functional/bor16.asm | 1 + tests/functional/bor32.asm | 1 + tests/functional/bound02.asm | 1 + tests/functional/bound03.asm | 1 + tests/functional/bxor16.asm | 2 ++ tests/functional/bxor32.asm | 1 + tests/functional/byref32.asm | 3 ++ tests/functional/byval32.asm | 2 ++ tests/functional/castF16toF.asm | 4 +++ tests/functional/chr.asm | 13 +++++++-- tests/functional/chr0.asm | 10 +++++-- tests/functional/chr1.asm | 11 ++++++-- tests/functional/circle.asm | 8 ++++++ tests/functional/code00.asm | 32 ++++++++++++++++++---- tests/functional/code01.asm | 32 ++++++++++++++++++---- tests/functional/code02.asm | 32 ++++++++++++++++++---- tests/functional/codecrash1.asm | 3 ++ tests/functional/codecrash2.asm | 11 ++++++-- tests/functional/codecrash3.asm | 10 +++++-- tests/functional/codecrash4.asm | 12 ++++++-- tests/functional/coercion1.asm | 10 +++++++ tests/functional/coercion3.asm | 9 ++++-- tests/functional/cpeq16.asm | 1 + tests/functional/div32.asm | 5 ++++ tests/functional/divf00.asm | 5 ++++ tests/functional/divf01.asm | 4 +++ tests/functional/divf16.asm | 3 ++ tests/functional/divf16a.asm | 3 ++ tests/functional/divf16b.asm | 3 ++ tests/functional/divf16c.asm | 4 +++ tests/functional/divi16a.asm | 2 ++ tests/functional/divi16b.asm | 2 ++ tests/functional/divi32c.asm | 3 ++ tests/functional/divi8.asm | 1 + tests/functional/divi8a.asm | 1 + tests/functional/divi8b.asm | 1 + tests/functional/divu16.asm | 2 ++ tests/functional/divu16a.asm | 2 ++ tests/functional/divu16b.asm | 2 ++ tests/functional/divu32c.asm | 3 ++ tests/functional/divu8.asm | 1 + tests/functional/divu8a.asm | 1 + tests/functional/divu8b.asm | 1 + tests/functional/draw.asm | 11 ++++++++ tests/functional/draw3.asm | 14 ++++++++++ tests/functional/einarattr.asm | 24 ++++++++++++++-- tests/functional/einarshift.asm | 25 +++++++++++++++-- tests/functional/elseif3.asm | 2 ++ tests/functional/elseif5.asm | 2 ++ tests/functional/elseif6.asm | 2 ++ tests/functional/emptystrparam.asm | 9 ++++-- tests/functional/eq0.asm | 6 ++++ tests/functional/fastcall0.asm | 31 ++++++++++++++------- tests/functional/for0.asm | 29 ++++++++++++++++++-- tests/functional/fporder.asm | 6 ++++ tests/functional/gef16.asm | 3 ++ tests/functional/gei32.asm | 3 ++ tests/functional/gei8.asm | 1 + tests/functional/geu32.asm | 2 ++ tests/functional/gtf16.asm | 3 ++ tests/functional/gti32.asm | 3 ++ tests/functional/gti8.asm | 2 ++ tests/functional/gtu32.asm | 1 + tests/functional/ifelse1.asm | 24 ++++++++++++++-- tests/functional/ifthen.asm | 2 ++ tests/functional/ifthenelse.asm | 2 ++ tests/functional/ifthenelseif.asm | 2 ++ tests/functional/inkey.asm | 32 +++++++++++++++++++--- tests/functional/inktemp.asm | 23 ++++++++++++++-- tests/functional/lcd3.asm | 41 +++++++++++++++++++++++++--- tests/functional/lcd7.asm | 35 +++++++++++++++++++++--- tests/functional/lcd8.asm | 31 ++++++++++++++++++--- tests/functional/lcd9.asm | 34 ++++++++++++++++++++--- tests/functional/lef16.asm | 3 ++ tests/functional/lei32.asm | 3 ++ tests/functional/leu32.asm | 1 + tests/functional/load02.asm | 32 ++++++++++++++++++---- tests/functional/load03.asm | 32 ++++++++++++++++++---- tests/functional/loadstr.asm | 16 +++++++++-- tests/functional/loadu16ii.asm | 27 ++++++++++++++++-- tests/functional/ltee1.asm | 39 +++++++++++++++++++++++--- tests/functional/ltee3.asm | 9 ++++-- tests/functional/ltee5.asm | 12 ++++++-- tests/functional/ltee6.asm | 27 ++++++++++++------ tests/functional/ltee7.asm | 28 +++++++++++++------ tests/functional/ltee9.asm | 7 +++++ tests/functional/ltf16.asm | 3 ++ tests/functional/lti32c.asm | 3 ++ tests/functional/ltu32c.asm | 2 ++ tests/functional/mcleod.asm | 5 ++++ tests/functional/mcleod2.asm | 11 ++++++-- tests/functional/modf16c.asm | 7 +++++ tests/functional/modi32c.asm | 3 ++ tests/functional/modi8.asm | 1 + tests/functional/modi8a.asm | 1 + tests/functional/modi8b.asm | 1 + tests/functional/modu32c.asm | 3 ++ tests/functional/modu8.asm | 1 + tests/functional/modu8a.asm | 1 + tests/functional/modu8b.asm | 1 + tests/functional/mul16.asm | 1 + tests/functional/mul16a.asm | 1 + tests/functional/mul16b.asm | 1 + tests/functional/mul8.asm | 1 + tests/functional/mul8a.asm | 1 + tests/functional/mul8b.asm | 1 + tests/functional/mulf00.asm | 4 +++ tests/functional/mulf01.asm | 3 ++ tests/functional/mulf16a.asm | 3 ++ tests/functional/ongoto.asm | 25 +++++++++++++++-- tests/functional/opt2_pstr.asm | 9 ++++-- tests/functional/opt3_einar.asm | 24 ++++++++++++++-- tests/functional/opt3_lcd5.asm | 6 ++++ tests/functional/opt3_sp.asm | 8 ++++++ tests/functional/optconst.asm | 26 ++++++++++++++++-- tests/functional/or32.asm | 1 + tests/functional/out0.asm | 2 ++ tests/functional/param0.asm | 32 +++++++++++++++++++--- tests/functional/param1.asm | 33 +++++++++++++++++++--- tests/functional/param2.asm | 32 +++++++++++++++++++--- tests/functional/parambyref1.asm | 26 ++++++++++++++++-- tests/functional/paramstr3.asm | 9 ++++-- tests/functional/paramstr4.asm | 9 ++++-- tests/functional/paramstr5.asm | 9 ++++-- tests/functional/plot.asm | 7 +++++ tests/functional/pooky0.asm | 8 ++++++ tests/functional/print.asm | 44 +++++++++++++++++++++++++++--- tests/functional/print42.asm | 2 ++ tests/functional/print64.asm | 2 ++ tests/functional/randomize.asm | 1 + tests/functional/save01.asm | 9 ++++-- tests/functional/save02.asm | 9 ++++-- tests/functional/save03.asm | 9 ++++-- tests/functional/sgnf.asm | 2 ++ tests/functional/sgnf16.asm | 2 ++ tests/functional/sgni16.asm | 2 ++ tests/functional/sgni32.asm | 2 ++ tests/functional/sgni8.asm | 1 + tests/functional/sgnu16.asm | 1 + tests/functional/sgnu32.asm | 1 + tests/functional/sgnu8.asm | 1 + tests/functional/sigilfunc.asm | 10 +++++-- tests/functional/simple.asm | 24 ++++++++++++++-- tests/functional/slice0.asm | 11 ++++++-- tests/functional/slice2.asm | 15 ++++++++-- tests/functional/spfill.asm | 31 ++++++++++++++------- tests/functional/stoperr.asm | 1 + tests/functional/storecstr.asm | 11 ++++++-- tests/functional/storef.asm | 1 + tests/functional/storestr0.asm | 11 ++++++-- tests/functional/storestr1.asm | 12 ++++++-- tests/functional/storestr2.asm | 13 +++++++-- tests/functional/str0.asm | 36 +++++++++++++++++++++--- tests/functional/str00.asm | 11 ++++++-- tests/functional/str01.asm | 14 ++++++++-- tests/functional/str02.asm | 16 +++++++++-- tests/functional/stradd.asm | 14 ++++++++-- tests/functional/strbase.asm | 16 +++++++++-- tests/functional/strbase2.asm | 38 +++++++++++++++++++++++--- tests/functional/stringfunc.asm | 9 ++++-- tests/functional/stringparam.asm | 31 ++++++++++++++++++--- tests/functional/strlocal0.asm | 34 ++++++++++++++++++++--- tests/functional/strparam0.asm | 31 ++++++++++++++++++--- tests/functional/strparam1.asm | 19 +++++++++++-- tests/functional/strparam2.asm | 33 +++++++++++++++++++--- tests/functional/strparam3.asm | 31 ++++++++++++++++++--- tests/functional/strsigil.asm | 13 +++++++-- tests/functional/subf00.asm | 4 +++ tests/functional/subf01.asm | 3 ++ tests/functional/subf16c.asm | 2 ++ tests/functional/subi32c.asm | 2 ++ tests/functional/substrlval.asm | 13 +++++++-- tests/functional/subu32c.asm | 2 ++ tests/functional/usr0.asm | 29 ++++++++++++++++++-- tests/functional/valcrash2.asm | 14 ++++++++-- tests/functional/while.asm | 6 ++++ tests/functional/xor16.asm | 2 ++ tests/functional/xor32.asm | 2 ++ tests/functional/xor8.asm | 1 + 220 files changed, 1941 insertions(+), 326 deletions(-) diff --git a/tests/functional/19.asm b/tests/functional/19.asm index 70ab7c141..d6a117d4a 100644 --- a/tests/functional/19.asm +++ b/tests/functional/19.asm @@ -81,7 +81,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "acos.asm" + #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -142,6 +144,7 @@ ACOS: ; Computes ACOS using ROM FP-CALC #line 1 "asin.asm" + ASIN: ; Computes ASIN using ROM FP-CALC call __FPSTACK_PUSH @@ -155,6 +158,7 @@ ASIN: ; Computes ASIN using ROM FP-CALC #line 1 "atan.asm" + ATAN: ; Computes ATAN using ROM FP-CALC call __FPSTACK_PUSH @@ -168,6 +172,7 @@ ATAN: ; Computes ATAN using ROM FP-CALC #line 1 "cos.asm" + COS: ; Computes COS using ROM FP-CALC call __FPSTACK_PUSH @@ -181,6 +186,7 @@ COS: ; Computes COS using ROM FP-CALC #line 1 "exp.asm" + EXP: ; Computes e^n using ROM FP-CALC call __FPSTACK_PUSH @@ -194,6 +200,7 @@ EXP: ; Computes e^n using ROM FP-CALC #line 1 "logn.asm" + LN: ; Computes Ln(x) using ROM FP-CALC call __FPSTACK_PUSH @@ -207,6 +214,7 @@ LN: ; Computes Ln(x) using ROM FP-CALC #line 1 "sin.asm" + SIN: ; Computes SIN using ROM FP-CALC call __FPSTACK_PUSH @@ -220,6 +228,7 @@ SIN: ; Computes SIN using ROM FP-CALC #line 1 "sqrt.asm" + SQRT: ; Computes SQRT(x) using ROM FP-CALC call __FPSTACK_PUSH @@ -231,6 +240,7 @@ SQRT: ; Computes SQRT(x) using ROM FP-CALC #line 79 "19.bas" #line 1 "storef.asm" + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -263,6 +273,7 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL #line 1 "tan.asm" + TAN: ; Computes TAN using ROM FP-CALC call __FPSTACK_PUSH diff --git a/tests/functional/21.asm b/tests/functional/21.asm index 923866203..ca4e0df84 100644 --- a/tests/functional/21.asm +++ b/tests/functional/21.asm @@ -32,6 +32,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "storef.asm" + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL diff --git a/tests/functional/25.asm b/tests/functional/25.asm index 3b5f8858b..9541c9092 100644 --- a/tests/functional/25.asm +++ b/tests/functional/25.asm @@ -35,6 +35,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "not32.asm" + ; ------------------------------------------------------------- ; 32 bit logical NOT ; ------------------------------------------------------------- diff --git a/tests/functional/27.asm b/tests/functional/27.asm index 7618aa024..c93e73b0b 100644 --- a/tests/functional/27.asm +++ b/tests/functional/27.asm @@ -42,6 +42,7 @@ __LABEL0: DEFB 49h DEFB 43h #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -55,7 +56,9 @@ __LABEL0: #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -125,6 +128,7 @@ __LABEL0: #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -166,6 +170,7 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -235,6 +240,7 @@ __STOP: #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -398,9 +404,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -477,6 +483,7 @@ __MEM_SUBTRACT: #line 71 "realloc.asm" #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/28.asm b/tests/functional/28.asm index b5d8a2c3d..0b1d7089c 100644 --- a/tests/functional/28.asm +++ b/tests/functional/28.asm @@ -45,6 +45,7 @@ __LABEL0: DEFB 49h DEFB 43h #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -58,7 +59,9 @@ __LABEL0: #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -128,6 +131,7 @@ __LABEL0: #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -169,6 +173,7 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -238,6 +243,7 @@ __STOP: #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -401,9 +407,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -480,6 +486,7 @@ __MEM_SUBTRACT: #line 71 "realloc.asm" #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -887,6 +894,7 @@ __STORE_STR: #line 33 "28.bas" #line 1 "strlen.asm" + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL diff --git a/tests/functional/29.asm b/tests/functional/29.asm index e42ed147e..90027a708 100644 --- a/tests/functional/29.asm +++ b/tests/functional/29.asm @@ -51,6 +51,7 @@ __LABEL0: DEFB 49h DEFB 43h #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -119,6 +120,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -160,6 +162,7 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -323,9 +326,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/home/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/home/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -402,6 +405,7 @@ __MEM_SUBTRACT: #line 39 "29.bas" #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -415,7 +419,9 @@ __MEM_SUBTRACT: #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -487,6 +493,7 @@ __MEM_SUBTRACT: #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -895,7 +902,9 @@ __STORE_STR: #line 40 "29.bas" #line 1 "strcat.asm" + #line 1 "strlen.asm" + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL diff --git a/tests/functional/31.asm b/tests/functional/31.asm index 46a7d5e02..6d8864ba7 100644 --- a/tests/functional/31.asm +++ b/tests/functional/31.asm @@ -43,7 +43,9 @@ _test__leave: pop ix ret #line 1 "addf.asm" + #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -113,6 +115,7 @@ __ADDF: ; Addition #line 34 "31.bas" #line 1 "pushf.asm" + ; Routine to push Float pointed by HL ; Into the stack. Notice that the hl points to the last ; byte of the FP number. @@ -142,6 +145,7 @@ __FP_PUSH_REV: #line 35 "31.bas" #line 1 "storef.asm" + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL diff --git a/tests/functional/34.asm b/tests/functional/34.asm index a6361474e..e0310dbd8 100644 --- a/tests/functional/34.asm +++ b/tests/functional/34.asm @@ -42,7 +42,9 @@ _test__leave: exx ret #line 1 "u32tofreg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z diff --git a/tests/functional/35.asm b/tests/functional/35.asm index 6a3cc568e..ae5271d4c 100644 --- a/tests/functional/35.asm +++ b/tests/functional/35.asm @@ -55,7 +55,9 @@ _test__leave: exx ret #line 1 "addf.asm" + #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -124,12 +126,14 @@ __ADDF: ; Addition #line 46 "35.bas" #line 1 "ploadf.asm" + ; Parameter / Local var load ; A => Offset ; IX = Stack Frame ; RESULT: HL => IX + DE #line 1 "iloadf.asm" + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL @@ -168,7 +172,9 @@ __PLOADF: #line 47 "35.bas" #line 1 "u32tofreg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z diff --git a/tests/functional/36.asm b/tests/functional/36.asm index 9879c8b08..1755b1c51 100644 --- a/tests/functional/36.asm +++ b/tests/functional/36.asm @@ -58,7 +58,9 @@ _test__leave: exx ret #line 1 "addf.asm" + #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -127,12 +129,14 @@ __ADDF: ; Addition #line 49 "36.bas" #line 1 "ploadf.asm" + ; Parameter / Local var load ; A => Offset ; IX = Stack Frame ; RESULT: HL => IX + DE #line 1 "iloadf.asm" + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL @@ -171,7 +175,9 @@ __PLOADF: #line 50 "36.bas" #line 1 "u32tofreg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z diff --git a/tests/functional/37.asm b/tests/functional/37.asm index 45bdeb647..d68a43526 100644 --- a/tests/functional/37.asm +++ b/tests/functional/37.asm @@ -58,7 +58,9 @@ _test__leave: exx ret #line 1 "addf.asm" + #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -127,12 +129,14 @@ __ADDF: ; Addition #line 49 "37.bas" #line 1 "ploadf.asm" + ; Parameter / Local var load ; A => Offset ; IX = Stack Frame ; RESULT: HL => IX + DE #line 1 "iloadf.asm" + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL @@ -171,7 +175,9 @@ __PLOADF: #line 50 "37.bas" #line 1 "u32tofreg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z diff --git a/tests/functional/38.asm b/tests/functional/38.asm index 4009c862b..b20128e39 100644 --- a/tests/functional/38.asm +++ b/tests/functional/38.asm @@ -58,7 +58,9 @@ _test__leave: exx ret #line 1 "addf.asm" + #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -127,12 +129,14 @@ __ADDF: ; Addition #line 49 "38.bas" #line 1 "ploadf.asm" + ; Parameter / Local var load ; A => Offset ; IX = Stack Frame ; RESULT: HL => IX + DE #line 1 "iloadf.asm" + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL @@ -171,7 +175,9 @@ __PLOADF: #line 50 "38.bas" #line 1 "u32tofreg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z diff --git a/tests/functional/39.asm b/tests/functional/39.asm index cc78543fd..45bed186a 100644 --- a/tests/functional/39.asm +++ b/tests/functional/39.asm @@ -60,7 +60,9 @@ _test__leave: exx ret #line 1 "u32tofreg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z diff --git a/tests/functional/40.asm b/tests/functional/40.asm index d806949aa..01df4667e 100644 --- a/tests/functional/40.asm +++ b/tests/functional/40.asm @@ -53,7 +53,9 @@ _test__leave: exx ret #line 1 "u32tofreg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z diff --git a/tests/functional/43.asm b/tests/functional/43.asm index b47235693..8f1e3aa3c 100644 --- a/tests/functional/43.asm +++ b/tests/functional/43.asm @@ -58,7 +58,9 @@ _test__leave: exx ret #line 1 "u32tofreg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z diff --git a/tests/functional/46.asm b/tests/functional/46.asm index 46afdab1f..a1a15407e 100644 --- a/tests/functional/46.asm +++ b/tests/functional/46.asm @@ -42,6 +42,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "array.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -61,6 +62,7 @@ __CALL_BACK__: #line 1 "mul16.asm" + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned @@ -116,7 +118,7 @@ __MUL16NOADD: #line 20 "array.asm" -#line 24 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 24 "/src/zxb/trunk/library-asm/array.asm" __ARRAY: PROC @@ -138,12 +140,12 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 48 "/src/zxb/trunk/library-asm/array.asm" LOOP: pop bc ; Get next index (Ai) from the stack -#line 60 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 60 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -161,10 +163,10 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -175,7 +177,7 @@ ARRAY_END: push de exx -#line 100 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -206,7 +208,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 131 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/47.asm b/tests/functional/47.asm index b3925394d..7dd550412 100644 --- a/tests/functional/47.asm +++ b/tests/functional/47.asm @@ -69,6 +69,7 @@ _test__leave: pop ix ret #line 1 "array.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -88,6 +89,7 @@ _test__leave: #line 1 "mul16.asm" + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned @@ -143,7 +145,7 @@ __MUL16NOADD: #line 20 "array.asm" -#line 24 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 24 "/src/zxb/trunk/library-asm/array.asm" __ARRAY: PROC @@ -165,12 +167,12 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 48 "/src/zxb/trunk/library-asm/array.asm" LOOP: pop bc ; Get next index (Ai) from the stack -#line 60 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 60 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -188,10 +190,10 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -202,7 +204,7 @@ ARRAY_END: push de exx -#line 100 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -233,7 +235,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 131 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/48.asm b/tests/functional/48.asm index f6eaf5ede..66e72f0b7 100644 --- a/tests/functional/48.asm +++ b/tests/functional/48.asm @@ -53,6 +53,7 @@ __LABEL0: DEFB 49h DEFB 43h #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -66,7 +67,9 @@ __LABEL0: #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -136,6 +139,7 @@ __LABEL0: #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -177,6 +181,7 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -246,6 +251,7 @@ __STOP: #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -409,9 +415,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -488,6 +494,7 @@ __MEM_SUBTRACT: #line 71 "realloc.asm" #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -895,6 +902,7 @@ __STORE_STR: #line 41 "48.bas" #line 1 "storestr2.asm" + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication @@ -936,6 +944,7 @@ __STORE_STR2: #line 42 "48.bas" #line 1 "strslice.asm" + ; String slicing library ; HL = Str pointer ; DE = String start @@ -953,6 +962,7 @@ __STORE_STR2: ; #line 1 "strlen.asm" + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL diff --git a/tests/functional/49.asm b/tests/functional/49.asm index e8061dc86..6da77f964 100644 --- a/tests/functional/49.asm +++ b/tests/functional/49.asm @@ -53,6 +53,7 @@ __LABEL0: DEFB 49h DEFB 43h #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -66,7 +67,9 @@ __LABEL0: #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -136,6 +139,7 @@ __LABEL0: #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -177,6 +181,7 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -246,6 +251,7 @@ __STOP: #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -409,9 +415,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -488,6 +494,7 @@ __MEM_SUBTRACT: #line 71 "realloc.asm" #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -895,6 +902,7 @@ __STORE_STR: #line 41 "49.bas" #line 1 "storestr2.asm" + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication @@ -936,6 +944,7 @@ __STORE_STR2: #line 42 "49.bas" #line 1 "strslice.asm" + ; String slicing library ; HL = Str pointer ; DE = String start @@ -953,6 +962,7 @@ __STORE_STR2: ; #line 1 "strlen.asm" + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL diff --git a/tests/functional/55.asm b/tests/functional/55.asm index 4c649bd81..88ed39ac0 100644 --- a/tests/functional/55.asm +++ b/tests/functional/55.asm @@ -37,6 +37,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "array.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -56,6 +57,7 @@ __CALL_BACK__: #line 1 "mul16.asm" + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned @@ -111,7 +113,7 @@ __MUL16NOADD: #line 20 "array.asm" -#line 24 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 24 "/src/zxb/trunk/library-asm/array.asm" __ARRAY: PROC @@ -133,12 +135,12 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 48 "/src/zxb/trunk/library-asm/array.asm" LOOP: pop bc ; Get next index (Ai) from the stack -#line 60 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 60 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -156,10 +158,10 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -170,7 +172,7 @@ ARRAY_END: push de exx -#line 100 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -201,7 +203,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 131 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/abs32.asm b/tests/functional/abs32.asm index 03cb5a591..c1fe68864 100644 --- a/tests/functional/abs32.asm +++ b/tests/functional/abs32.asm @@ -32,10 +32,12 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "abs32.asm" + ; 16 bit signed integer abs value ; HL = value #line 1 "neg32.asm" + __ABS32: bit 7, d ret z diff --git a/tests/functional/addstr.asm b/tests/functional/addstr.asm index f1ee0c226..9b4521f23 100644 --- a/tests/functional/addstr.asm +++ b/tests/functional/addstr.asm @@ -65,6 +65,7 @@ __LABEL1: DEFW 0001h DEFB 31h #line 1 "storestr2.asm" + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication @@ -73,6 +74,7 @@ __LABEL1: ; freeing (HL) previously. #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -141,6 +143,7 @@ __LABEL1: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -422,7 +425,9 @@ __STORE_STR2: #line 53 "addstr.bas" #line 1 "strcat.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -491,6 +496,7 @@ __STORE_STR2: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -569,9 +575,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -648,6 +654,7 @@ __MEM_SUBTRACT: #line 2 "strcat.asm" #line 1 "strlen.asm" + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL diff --git a/tests/functional/aloadstr0.asm b/tests/functional/aloadstr0.asm index b33cdaa92..1bfc2a8fb 100644 --- a/tests/functional/aloadstr0.asm +++ b/tests/functional/aloadstr0.asm @@ -35,7 +35,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -104,6 +106,7 @@ __CALL_BACK__: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -145,6 +148,7 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -308,9 +312,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -430,6 +434,7 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 23 "aloadstr0.bas" #line 1 "storestr2.asm" + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication @@ -438,6 +443,7 @@ __LOADSTR: ; __FASTCALL__ entry ; freeing (HL) previously. #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/aloadstr1.asm b/tests/functional/aloadstr1.asm index 12f0ee994..b28d01b0b 100644 --- a/tests/functional/aloadstr1.asm +++ b/tests/functional/aloadstr1.asm @@ -40,6 +40,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "array.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -59,6 +60,7 @@ __CALL_BACK__: #line 1 "mul16.asm" + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned @@ -114,7 +116,7 @@ __MUL16NOADD: #line 20 "array.asm" -#line 24 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 24 "/src/zxb/trunk/library-asm/array.asm" __ARRAY: PROC @@ -136,12 +138,12 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 48 "/src/zxb/trunk/library-asm/array.asm" LOOP: pop bc ; Get next index (Ai) from the stack -#line 60 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 60 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -159,10 +161,10 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -173,7 +175,7 @@ ARRAY_END: push de exx -#line 100 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -204,7 +206,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 131 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start @@ -241,7 +243,9 @@ __FNMUL2: #line 28 "aloadstr1.bas" #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -310,6 +314,7 @@ __FNMUL2: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -351,6 +356,7 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -514,9 +520,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -636,6 +642,7 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 29 "aloadstr1.bas" #line 1 "storestr2.asm" + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication @@ -644,6 +651,7 @@ __LOADSTR: ; __FASTCALL__ entry ; freeing (HL) previously. #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/and16.asm b/tests/functional/and16.asm index a5558fd73..be06d866a 100644 --- a/tests/functional/and16.asm +++ b/tests/functional/and16.asm @@ -45,6 +45,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "and16.asm" + ; FASTCALL boolean and 16 version. ; result in Accumulator (0 False, not 0 True) ; __FASTCALL__ version (operands: DE, HL) diff --git a/tests/functional/and32.asm b/tests/functional/and32.asm index 7a0e55f41..4b49a32f1 100644 --- a/tests/functional/and32.asm +++ b/tests/functional/and32.asm @@ -55,6 +55,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "and32.asm" + ; FASTCALL boolean and 32 version. ; Performs 32bit and 32bit and returns the boolean ; result in Accumulator (0 False, not 0 True) diff --git a/tests/functional/and8.asm b/tests/functional/and8.asm index 9debbe01e..edc664afd 100644 --- a/tests/functional/and8.asm +++ b/tests/functional/and8.asm @@ -41,6 +41,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "and8.asm" + ; FASTCALL boolean and 8 version. ; result in Accumulator (0 False, not 0 True) ; __FASTCALL__ version (operands: A, H) diff --git a/tests/functional/arden2.asm b/tests/functional/arden2.asm index 866fa9884..607d1b825 100644 --- a/tests/functional/arden2.asm +++ b/tests/functional/arden2.asm @@ -45,6 +45,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -113,6 +114,7 @@ __CALL_BACK__: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -154,6 +156,7 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -317,9 +320,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -396,6 +399,7 @@ __MEM_SUBTRACT: #line 33 "arden2.bas" #line 1 "chr.asm" + ; CHR$(x, y, x) returns the string CHR$(x) + CHR$(y) + CHR$(z) ; @@ -473,6 +477,7 @@ __CHR_END: #line 34 "arden2.bas" #line 1 "storestr2.asm" + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication @@ -481,6 +486,7 @@ __CHR_END: ; freeing (HL) previously. #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -705,7 +711,9 @@ __STORE_STR2: #line 35 "arden2.bas" #line 1 "strcat.asm" + #line 1 "strlen.asm" + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL diff --git a/tests/functional/array03.asm b/tests/functional/array03.asm index bb20aaf13..41211ce29 100644 --- a/tests/functional/array03.asm +++ b/tests/functional/array03.asm @@ -35,6 +35,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "array.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -54,6 +55,7 @@ __CALL_BACK__: #line 1 "mul16.asm" + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned @@ -109,7 +111,7 @@ __MUL16NOADD: #line 20 "array.asm" -#line 24 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 24 "/src/zxb/trunk/library-asm/array.asm" __ARRAY: PROC @@ -131,12 +133,12 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 48 "/src/zxb/trunk/library-asm/array.asm" LOOP: pop bc ; Get next index (Ai) from the stack -#line 60 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 60 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -154,10 +156,10 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -168,7 +170,7 @@ ARRAY_END: push de exx -#line 100 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -199,7 +201,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 131 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/array06.asm b/tests/functional/array06.asm index 3ca57bcaa..273e9ef70 100644 --- a/tests/functional/array06.asm +++ b/tests/functional/array06.asm @@ -35,6 +35,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "array.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -54,6 +55,7 @@ __CALL_BACK__: #line 1 "mul16.asm" + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned @@ -109,7 +111,7 @@ __MUL16NOADD: #line 20 "array.asm" -#line 24 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 24 "/src/zxb/trunk/library-asm/array.asm" __ARRAY: PROC @@ -131,12 +133,12 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 48 "/src/zxb/trunk/library-asm/array.asm" LOOP: pop bc ; Get next index (Ai) from the stack -#line 60 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 60 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -154,10 +156,10 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -168,7 +170,7 @@ ARRAY_END: push de exx -#line 100 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -199,7 +201,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 131 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/array07.asm b/tests/functional/array07.asm index fd0837b3b..b32426267 100644 --- a/tests/functional/array07.asm +++ b/tests/functional/array07.asm @@ -58,6 +58,7 @@ _test__leave: exx ret #line 1 "array.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -77,6 +78,7 @@ _test__leave: #line 1 "mul16.asm" + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned @@ -132,7 +134,7 @@ __MUL16NOADD: #line 20 "array.asm" -#line 24 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 24 "/src/zxb/trunk/library-asm/array.asm" __ARRAY: PROC @@ -154,12 +156,12 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 48 "/src/zxb/trunk/library-asm/array.asm" LOOP: pop bc ; Get next index (Ai) from the stack -#line 60 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 60 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -177,10 +179,10 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -191,7 +193,7 @@ ARRAY_END: push de exx -#line 100 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -222,7 +224,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 131 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start @@ -259,6 +261,7 @@ __FNMUL2: #line 46 "array07.bas" #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -327,6 +330,7 @@ __FNMUL2: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -576,6 +580,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 47 "array07.bas" #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -589,7 +594,9 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -659,6 +666,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -700,6 +708,7 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -806,9 +815,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl diff --git a/tests/functional/array09.asm b/tests/functional/array09.asm index dbe33c68b..a1da94d0d 100644 --- a/tests/functional/array09.asm +++ b/tests/functional/array09.asm @@ -36,6 +36,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "array.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -55,6 +56,7 @@ __CALL_BACK__: #line 1 "mul16.asm" + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned @@ -110,7 +112,7 @@ __MUL16NOADD: #line 20 "array.asm" -#line 24 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 24 "/src/zxb/trunk/library-asm/array.asm" __ARRAY: PROC @@ -132,12 +134,12 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 48 "/src/zxb/trunk/library-asm/array.asm" LOOP: pop bc ; Get next index (Ai) from the stack -#line 60 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 60 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -155,10 +157,10 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -169,7 +171,7 @@ ARRAY_END: push de exx -#line 100 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -200,7 +202,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 131 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start @@ -237,6 +239,7 @@ __FNMUL2: #line 24 "array09.bas" #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -250,7 +253,9 @@ __FNMUL2: #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -320,6 +325,7 @@ __FNMUL2: #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -361,6 +367,7 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -430,6 +437,7 @@ __STOP: #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -593,9 +601,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -672,6 +680,7 @@ __MEM_SUBTRACT: #line 71 "realloc.asm" #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/array10.asm b/tests/functional/array10.asm index 817147528..bf7d50aeb 100644 --- a/tests/functional/array10.asm +++ b/tests/functional/array10.asm @@ -68,6 +68,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "array.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -87,6 +88,7 @@ __CALL_BACK__: #line 1 "mul16.asm" + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned @@ -142,7 +144,7 @@ __MUL16NOADD: #line 20 "array.asm" -#line 24 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 24 "/src/zxb/trunk/library-asm/array.asm" __ARRAY: PROC @@ -164,12 +166,12 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 48 "/src/zxb/trunk/library-asm/array.asm" LOOP: pop bc ; Get next index (Ai) from the stack -#line 60 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 60 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -187,10 +189,10 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -201,7 +203,7 @@ ARRAY_END: push de exx -#line 100 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -232,7 +234,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 131 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/astore16.asm b/tests/functional/astore16.asm index 6e75a7fd0..d8998625a 100644 --- a/tests/functional/astore16.asm +++ b/tests/functional/astore16.asm @@ -63,6 +63,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "array.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -82,6 +83,7 @@ __CALL_BACK__: #line 1 "mul16.asm" + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned @@ -137,7 +139,7 @@ __MUL16NOADD: #line 20 "array.asm" -#line 24 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 24 "/src/zxb/trunk/library-asm/array.asm" __ARRAY: PROC @@ -159,12 +161,12 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 48 "/src/zxb/trunk/library-asm/array.asm" LOOP: pop bc ; Get next index (Ai) from the stack -#line 60 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 60 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -182,10 +184,10 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -196,7 +198,7 @@ ARRAY_END: push de exx -#line 100 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -227,7 +229,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 131 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start @@ -264,11 +266,13 @@ __FNMUL2: #line 53 "astore16.bas" #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -302,6 +306,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -352,7 +357,9 @@ __CLS_SCR: #line 7 "print.asm" #line 1 "in_screen.asm" + #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -423,6 +430,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -441,10 +449,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -497,6 +507,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -545,6 +556,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -572,6 +584,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -601,12 +614,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -665,7 +680,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -723,6 +738,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -756,6 +772,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -788,6 +805,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -823,6 +841,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1370,11 +1389,14 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes #line 54 "astore16.bas" #line 1 "printu16.asm" + #line 1 "printi16.asm" + #line 1 "printnum.asm" + __PRINTU_START: PROC @@ -1408,10 +1430,12 @@ __PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers #line 2 "printi16.asm" #line 1 "div16.asm" + ; 16 bit division and modulo functions ; for both signed and unsigned values #line 1 "neg16.asm" + ; Negates HL value (16 bit) __ABS16: bit 7, h diff --git a/tests/functional/atlabel1.asm b/tests/functional/atlabel1.asm index 23784599c..cd16cb67b 100644 --- a/tests/functional/atlabel1.asm +++ b/tests/functional/atlabel1.asm @@ -34,6 +34,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "storef.asm" + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL diff --git a/tests/functional/attr.asm b/tests/functional/attr.asm index 9880b812d..01a58f42a 100644 --- a/tests/functional/attr.asm +++ b/tests/functional/attr.asm @@ -42,12 +42,15 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -82,9 +85,9 @@ COPY_ATTR: __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) -#line 63 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 63 "/src/zxb/trunk/library-asm/copy_attr.asm" ret -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -128,6 +131,7 @@ BOLD_TMP: #line 33 "attr.bas" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -155,6 +159,7 @@ FLASH_TMP: #line 35 "attr.bas" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register @@ -200,6 +205,7 @@ INK_TMP: #line 36 "attr.bas" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register @@ -247,6 +253,7 @@ OVER_TMP: #line 37 "attr.bas" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register diff --git a/tests/functional/band16.asm b/tests/functional/band16.asm index d6b5bd4bc..85ad5ef50 100644 --- a/tests/functional/band16.asm +++ b/tests/functional/band16.asm @@ -56,6 +56,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "band16.asm" + ; vim:ts=4:et: ; FASTCALL bitwise and16 version. ; result in hl diff --git a/tests/functional/band32.asm b/tests/functional/band32.asm index e8dacc5ad..5a1529974 100644 --- a/tests/functional/band32.asm +++ b/tests/functional/band32.asm @@ -90,6 +90,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "band32.asm" + ; FASTCALL bitwise and 32 version. ; Performs 32bit and 32bit and returns the bitwise ; result in DE,HL diff --git a/tests/functional/band8.asm b/tests/functional/band8.asm index f0e0e2efd..c37f7afd6 100644 --- a/tests/functional/band8.asm +++ b/tests/functional/band8.asm @@ -55,6 +55,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "and8.asm" + ; FASTCALL boolean and 8 version. ; result in Accumulator (0 False, not 0 True) ; __FASTCALL__ version (operands: A, H) diff --git a/tests/functional/bitwise.asm b/tests/functional/bitwise.asm index 6e37840a1..b4d157f13 100644 --- a/tests/functional/bitwise.asm +++ b/tests/functional/bitwise.asm @@ -42,6 +42,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "and8.asm" + ; FASTCALL boolean and 8 version. ; result in Accumulator (0 False, not 0 True) ; __FASTCALL__ version (operands: A, H) diff --git a/tests/functional/bnot16.asm b/tests/functional/bnot16.asm index ad032b49b..c7bfe2440 100644 --- a/tests/functional/bnot16.asm +++ b/tests/functional/bnot16.asm @@ -38,6 +38,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "bnot16.asm" + ; vim:ts=4:et: ; FASTCALL bitwise or 16 version. ; result in HL diff --git a/tests/functional/bor16.asm b/tests/functional/bor16.asm index 54f534b3b..1b76a006d 100644 --- a/tests/functional/bor16.asm +++ b/tests/functional/bor16.asm @@ -56,6 +56,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "bor16.asm" + ; vim:ts=4:et: ; FASTCALL bitwise or 16 version. ; result in HL diff --git a/tests/functional/bor32.asm b/tests/functional/bor32.asm index 9f264a902..c4477f02c 100644 --- a/tests/functional/bor32.asm +++ b/tests/functional/bor32.asm @@ -90,6 +90,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "bor32.asm" + ; FASTCALL bitwise or 32 version. ; Performs 32bit or 32bit and returns the bitwise ; result DE,HL diff --git a/tests/functional/bound02.asm b/tests/functional/bound02.asm index 22abd845c..be2edcbff 100644 --- a/tests/functional/bound02.asm +++ b/tests/functional/bound02.asm @@ -52,6 +52,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "bound.asm" + ; --------------------------------------------------------- ; Copyleft (k)2011 by Jose Rodriguez (a.k.a. Boriel) ; http://www.boriel.com diff --git a/tests/functional/bound03.asm b/tests/functional/bound03.asm index d91f0cdad..a964fce16 100644 --- a/tests/functional/bound03.asm +++ b/tests/functional/bound03.asm @@ -52,6 +52,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "bound.asm" + ; --------------------------------------------------------- ; Copyleft (k)2011 by Jose Rodriguez (a.k.a. Boriel) ; http://www.boriel.com diff --git a/tests/functional/bxor16.asm b/tests/functional/bxor16.asm index 1c5b6241e..8c8243946 100644 --- a/tests/functional/bxor16.asm +++ b/tests/functional/bxor16.asm @@ -56,6 +56,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "bxor16.asm" + ; vim:ts=4:et: ; FASTCALL bitwise xor 16 version. ; result in Accumulator (0 False, not 0 True) @@ -77,6 +78,7 @@ __BXOR16: #line 47 "bxor16.bas" #line 1 "neg16.asm" + ; Negates HL value (16 bit) __ABS16: bit 7, h diff --git a/tests/functional/bxor32.asm b/tests/functional/bxor32.asm index cfbee71f6..95e767a31 100644 --- a/tests/functional/bxor32.asm +++ b/tests/functional/bxor32.asm @@ -90,6 +90,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "bxor32.asm" + ; FASTCALL bitwise xor 32 version. ; Performs 32bit xor 32bit and returns the bitwise ; result DE,HL diff --git a/tests/functional/byref32.asm b/tests/functional/byref32.asm index 1b59e1014..caa8894ef 100644 --- a/tests/functional/byref32.asm +++ b/tests/functional/byref32.asm @@ -61,6 +61,7 @@ _test__leave: exx ret #line 1 "iload32.asm" + ; __FASTCALL__ routine which ; loads a 32 bits integer into DE,HL ; stored at position pointed by POINTER HL @@ -80,7 +81,9 @@ __ILOAD32: #line 52 "byref32.bas" #line 1 "pistore32.asm" + #line 1 "store32.asm" + __PISTORE32: push hl push ix diff --git a/tests/functional/byval32.asm b/tests/functional/byval32.asm index 897336855..025a7262e 100644 --- a/tests/functional/byval32.asm +++ b/tests/functional/byval32.asm @@ -63,7 +63,9 @@ _test__leave: exx ret #line 1 "pstore32.asm" + #line 1 "store32.asm" + __PISTORE32: push hl push ix diff --git a/tests/functional/castF16toF.asm b/tests/functional/castF16toF.asm index 82f8f720e..95544ca4d 100644 --- a/tests/functional/castF16toF.asm +++ b/tests/functional/castF16toF.asm @@ -32,7 +32,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "f16tofreg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z @@ -66,6 +68,7 @@ __NEG32: ; Negates DEHL (Two's complement) #line 2 "f16tofreg.asm" #line 1 "u32tofreg.asm" + __I8TOFREG: ld l, a rlca @@ -203,6 +206,7 @@ __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) #line 23 "castF16toF.bas" #line 1 "storef.asm" + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL diff --git a/tests/functional/chr.asm b/tests/functional/chr.asm index 72155f35f..ee1fde6fc 100644 --- a/tests/functional/chr.asm +++ b/tests/functional/chr.asm @@ -44,10 +44,12 @@ __LABEL0: DEFW 0001h DEFB 21h #line 1 "chr.asm" + ; CHR$(x, y, x) returns the string CHR$(x) + CHR$(y) + CHR$(z) ; #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -116,6 +118,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -157,6 +160,7 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -320,9 +324,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -471,6 +475,7 @@ __CHR_END: #line 32 "chr.bas" #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -484,7 +489,9 @@ __CHR_END: #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -556,6 +563,7 @@ __CHR_END: #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -963,6 +971,7 @@ __STORE_STR: #line 33 "chr.bas" #line 1 "storestr2.asm" + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication diff --git a/tests/functional/chr0.asm b/tests/functional/chr0.asm index 77b4db652..2e882e1a6 100644 --- a/tests/functional/chr0.asm +++ b/tests/functional/chr0.asm @@ -43,10 +43,12 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "chr.asm" + ; CHR$(x, y, x) returns the string CHR$(x) + CHR$(y) + CHR$(z) ; #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -115,6 +117,7 @@ __CALL_BACK__: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -156,6 +159,7 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -319,9 +323,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -470,6 +474,7 @@ __CHR_END: #line 31 "chr0.bas" #line 1 "storestr2.asm" + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication @@ -478,6 +483,7 @@ __CHR_END: ; freeing (HL) previously. #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/chr1.asm b/tests/functional/chr1.asm index 4434ec7b6..e8aceb2b1 100644 --- a/tests/functional/chr1.asm +++ b/tests/functional/chr1.asm @@ -38,6 +38,7 @@ __LABEL0: DEFB 41h DEFB 21h #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -51,7 +52,9 @@ __LABEL0: #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -121,6 +124,7 @@ __LABEL0: #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -162,6 +166,7 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -231,6 +236,7 @@ __STOP: #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -394,9 +400,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -473,6 +479,7 @@ __MEM_SUBTRACT: #line 71 "realloc.asm" #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/circle.asm b/tests/functional/circle.asm index 4f0338724..34d50b9f0 100644 --- a/tests/functional/circle.asm +++ b/tests/functional/circle.asm @@ -85,10 +85,12 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "circle.asm" + ; Bresenham's like circle algorithm ; best known as Middle Point Circle drawing algorithm #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -130,6 +132,7 @@ __STOP: ret #line 5 "circle.asm" #line 1 "plot.asm" + ; MIXED __FASTCAL__ / __CALLE__ PLOT Function ; Plots a point into the screen calling the ZX ROM PLOT routine @@ -138,7 +141,9 @@ __STOP: #line 1 "in_screen.asm" + #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -201,6 +206,7 @@ __OUT_OF_SCREEN_ERR: ENDP #line 9 "plot.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -540,7 +546,9 @@ __CIRCLE_PLOT: ENDP #line 76 "circle.bas" #line 1 "ftou32reg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z diff --git a/tests/functional/code00.asm b/tests/functional/code00.asm index 921aa86e0..13a587c40 100644 --- a/tests/functional/code00.asm +++ b/tests/functional/code00.asm @@ -43,7 +43,9 @@ __CALL_BACK__: __LABEL0: DEFW 0000h #line 1 "load.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -112,6 +114,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -153,6 +156,7 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -316,9 +320,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -395,6 +399,7 @@ __MEM_SUBTRACT: #line 2 "load.asm" #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -586,11 +591,13 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 3 "load.asm" #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -624,6 +631,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -676,6 +684,7 @@ __CLS_SCR: + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) @@ -705,6 +714,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -723,10 +733,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -779,6 +791,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -827,6 +840,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -854,6 +868,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -883,10 +898,12 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -912,9 +929,9 @@ COPY_ATTR: __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) -#line 63 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 63 "/src/zxb/trunk/library-asm/copy_attr.asm" ret -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -972,6 +989,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -1005,6 +1023,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -1037,6 +1056,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -1072,6 +1092,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1900,6 +1921,7 @@ PRINT_TAPE_MSG: #line 1 "loadstr.asm" + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL diff --git a/tests/functional/code01.asm b/tests/functional/code01.asm index ff67b41b0..969e3331f 100644 --- a/tests/functional/code01.asm +++ b/tests/functional/code01.asm @@ -43,7 +43,9 @@ __CALL_BACK__: __LABEL0: DEFW 0000h #line 1 "load.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -112,6 +114,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -153,6 +156,7 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -316,9 +320,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -395,6 +399,7 @@ __MEM_SUBTRACT: #line 2 "load.asm" #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -586,11 +591,13 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 3 "load.asm" #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -624,6 +631,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -676,6 +684,7 @@ __CLS_SCR: + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) @@ -705,6 +714,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -723,10 +733,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -779,6 +791,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -827,6 +840,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -854,6 +868,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -883,10 +898,12 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -912,9 +929,9 @@ COPY_ATTR: __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) -#line 63 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 63 "/src/zxb/trunk/library-asm/copy_attr.asm" ret -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -972,6 +989,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -1005,6 +1023,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -1037,6 +1056,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -1072,6 +1092,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1900,6 +1921,7 @@ PRINT_TAPE_MSG: #line 1 "loadstr.asm" + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL diff --git a/tests/functional/code02.asm b/tests/functional/code02.asm index f40f7f797..fcba8da57 100644 --- a/tests/functional/code02.asm +++ b/tests/functional/code02.asm @@ -43,7 +43,9 @@ __CALL_BACK__: __LABEL0: DEFW 0000h #line 1 "load.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -112,6 +114,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -153,6 +156,7 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -316,9 +320,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -395,6 +399,7 @@ __MEM_SUBTRACT: #line 2 "load.asm" #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -586,11 +591,13 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 3 "load.asm" #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -624,6 +631,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -676,6 +684,7 @@ __CLS_SCR: + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) @@ -705,6 +714,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -723,10 +733,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -779,6 +791,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -827,6 +840,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -854,6 +868,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -883,10 +898,12 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -912,9 +929,9 @@ COPY_ATTR: __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) -#line 63 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 63 "/src/zxb/trunk/library-asm/copy_attr.asm" ret -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -972,6 +989,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -1005,6 +1023,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -1037,6 +1056,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -1072,6 +1092,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1900,6 +1921,7 @@ PRINT_TAPE_MSG: #line 1 "loadstr.asm" + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL diff --git a/tests/functional/codecrash1.asm b/tests/functional/codecrash1.asm index 213fb4a04..28fa2d37b 100644 --- a/tests/functional/codecrash1.asm +++ b/tests/functional/codecrash1.asm @@ -34,8 +34,10 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "asc.asm" + ; Returns the ascii code for the given str #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -104,6 +106,7 @@ __CALL_BACK__: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/codecrash2.asm b/tests/functional/codecrash2.asm index f69bf04b8..651f83076 100644 --- a/tests/functional/codecrash2.asm +++ b/tests/functional/codecrash2.asm @@ -36,8 +36,10 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "asc.asm" + ; Returns the ascii code for the given str #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -106,6 +108,7 @@ __CALL_BACK__: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -389,7 +392,9 @@ __ASC_END: ENDP #line 24 "codecrash2.bas" #line 1 "strcat.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -458,6 +463,7 @@ __ASC_END: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -536,9 +542,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -615,6 +621,7 @@ __MEM_SUBTRACT: #line 2 "strcat.asm" #line 1 "strlen.asm" + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL diff --git a/tests/functional/codecrash3.asm b/tests/functional/codecrash3.asm index 7ff4abc2a..e8160e71b 100644 --- a/tests/functional/codecrash3.asm +++ b/tests/functional/codecrash3.asm @@ -34,8 +34,10 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "asc.asm" + ; Returns the ascii code for the given str #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -104,6 +106,7 @@ __CALL_BACK__: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -387,12 +390,14 @@ __ASC_END: ENDP #line 22 "codecrash3.bas" #line 1 "inkey.asm" + ; INKEY Function ; Returns a string allocated in dynamic memory ; containing the string. ; An empty string otherwise. #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -461,6 +466,7 @@ __ASC_END: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -539,9 +545,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl diff --git a/tests/functional/codecrash4.asm b/tests/functional/codecrash4.asm index 858ecd965..08c20f9f2 100644 --- a/tests/functional/codecrash4.asm +++ b/tests/functional/codecrash4.asm @@ -44,8 +44,10 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "asc.asm" + ; Returns the ascii code for the given str #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -114,6 +116,7 @@ __CALL_BACK__: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -397,12 +400,14 @@ __ASC_END: ENDP #line 32 "codecrash4.bas" #line 1 "inkey.asm" + ; INKEY Function ; Returns a string allocated in dynamic memory ; containing the string. ; An empty string otherwise. #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -471,6 +476,7 @@ __ASC_END: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -549,9 +555,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -684,7 +690,9 @@ __EMPTY_INKEY: #line 33 "codecrash4.bas" #line 1 "strcat.asm" + #line 1 "strlen.asm" + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL diff --git a/tests/functional/coercion1.asm b/tests/functional/coercion1.asm index 6c19f1b5d..c4e656ee5 100644 --- a/tests/functional/coercion1.asm +++ b/tests/functional/coercion1.asm @@ -68,7 +68,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "addf.asm" + #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -137,6 +139,7 @@ __ADDF: ; Addition #line 59 "coercion1.bas" #line 1 "border.asm" + ; __FASTCALL__ Routine to change de border ; Parameter (color) specified in A register @@ -147,7 +150,9 @@ __ADDF: ; Addition #line 60 "coercion1.bas" #line 1 "divf.asm" + #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -248,7 +253,9 @@ __DIVBYZERO: #line 61 "coercion1.bas" #line 1 "ftou32reg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z @@ -357,6 +364,7 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A #line 62 "coercion1.bas" #line 1 "mul8.asm" + __MUL8: ; Performs 8bit x 8bit multiplication PROC @@ -412,6 +420,7 @@ __MUL8B: #line 1 "mulf.asm" + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) ; All of them uses A EDCB registers as 1st paramter. @@ -434,6 +443,7 @@ __MULF: ; Multiplication #line 64 "coercion1.bas" #line 1 "pushf.asm" + ; Routine to push Float pointed by HL ; Into the stack. Notice that the hl points to the last ; byte of the FP number. diff --git a/tests/functional/coercion3.asm b/tests/functional/coercion3.asm index c438448b8..b9c24c7e3 100644 --- a/tests/functional/coercion3.asm +++ b/tests/functional/coercion3.asm @@ -39,9 +39,11 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -76,9 +78,9 @@ COPY_ATTR: __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) -#line 63 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 63 "/src/zxb/trunk/library-asm/copy_attr.asm" ret -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -93,6 +95,7 @@ __REFRESH_TMP: #line 30 "coercion3.bas" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register diff --git a/tests/functional/cpeq16.asm b/tests/functional/cpeq16.asm index 5a54c2ef9..dba683a95 100644 --- a/tests/functional/cpeq16.asm +++ b/tests/functional/cpeq16.asm @@ -37,6 +37,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "eq16.asm" + __EQ16: ; Test if 16bit values HL == DE ; Returns result in A: 0 = False, FF = True xor a ; Reset carry flag diff --git a/tests/functional/div32.asm b/tests/functional/div32.asm index 18f1012da..97641dfcd 100644 --- a/tests/functional/div32.asm +++ b/tests/functional/div32.asm @@ -37,8 +37,11 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "negf.asm" + #line 1 "u32tofreg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z @@ -162,6 +165,7 @@ __U32TOFREG_END: #line 1 "ftou32reg.asm" + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) @@ -238,6 +242,7 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A #line 3 "negf.asm" #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- diff --git a/tests/functional/divf00.asm b/tests/functional/divf00.asm index e74a53fad..b32c2d839 100644 --- a/tests/functional/divf00.asm +++ b/tests/functional/divf00.asm @@ -35,7 +35,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "divf.asm" + #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -83,6 +85,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK jp __FPSTACK_PUSH #line 2 "divf.asm" #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -184,6 +187,7 @@ __DIVBYZERO: #line 26 "divf00.bas" #line 1 "pushf.asm" + ; Routine to push Float pointed by HL ; Into the stack. Notice that the hl points to the last ; byte of the FP number. @@ -213,6 +217,7 @@ __FP_PUSH_REV: #line 27 "divf00.bas" #line 1 "storef.asm" + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL diff --git a/tests/functional/divf01.asm b/tests/functional/divf01.asm index b2ddca57e..9c2562bd2 100644 --- a/tests/functional/divf01.asm +++ b/tests/functional/divf01.asm @@ -39,7 +39,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "divf.asm" + #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -87,6 +89,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK jp __FPSTACK_PUSH #line 2 "divf.asm" #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -187,6 +190,7 @@ __DIVBYZERO: #line 30 "divf01.bas" #line 1 "storef.asm" + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL diff --git a/tests/functional/divf16.asm b/tests/functional/divf16.asm index a39f3bdca..27e8e9581 100644 --- a/tests/functional/divf16.asm +++ b/tests/functional/divf16.asm @@ -94,8 +94,11 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "divf16.asm" + #line 1 "div32.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z diff --git a/tests/functional/divf16a.asm b/tests/functional/divf16a.asm index 3abdba819..84615fff7 100644 --- a/tests/functional/divf16a.asm +++ b/tests/functional/divf16a.asm @@ -41,8 +41,11 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "divf16.asm" + #line 1 "div32.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z diff --git a/tests/functional/divf16b.asm b/tests/functional/divf16b.asm index 8a8edaeae..4ed8f2f5c 100644 --- a/tests/functional/divf16b.asm +++ b/tests/functional/divf16b.asm @@ -51,8 +51,11 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "divf16.asm" + #line 1 "div32.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z diff --git a/tests/functional/divf16c.asm b/tests/functional/divf16c.asm index 4446fa316..40875bd66 100644 --- a/tests/functional/divf16c.asm +++ b/tests/functional/divf16c.asm @@ -77,8 +77,11 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "divf16.asm" + #line 1 "div32.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z @@ -335,6 +338,7 @@ __ENDF16DIV: ; Put the sign on the result #line 68 "divf16c.bas" #line 1 "swap32.asm" + ; Exchanges current DE HL with the ; ones in the stack diff --git a/tests/functional/divi16a.asm b/tests/functional/divi16a.asm index fd30e94ef..044265d25 100644 --- a/tests/functional/divi16a.asm +++ b/tests/functional/divi16a.asm @@ -33,10 +33,12 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div16.asm" + ; 16 bit division and modulo functions ; for both signed and unsigned values #line 1 "neg16.asm" + ; Negates HL value (16 bit) __ABS16: bit 7, h diff --git a/tests/functional/divi16b.asm b/tests/functional/divi16b.asm index 6c545a2ea..1741ee84f 100644 --- a/tests/functional/divi16b.asm +++ b/tests/functional/divi16b.asm @@ -40,10 +40,12 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div16.asm" + ; 16 bit division and modulo functions ; for both signed and unsigned values #line 1 "neg16.asm" + ; Negates HL value (16 bit) __ABS16: bit 7, h diff --git a/tests/functional/divi32c.asm b/tests/functional/divi32c.asm index 7a4148dbc..642c4fb77 100644 --- a/tests/functional/divi32c.asm +++ b/tests/functional/divi32c.asm @@ -80,7 +80,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div32.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z @@ -254,6 +256,7 @@ __MODI32: ; 32bits signed division modulus #line 71 "divi32c.bas" #line 1 "swap32.asm" + ; Exchanges current DE HL with the ; ones in the stack diff --git a/tests/functional/divi8.asm b/tests/functional/divi8.asm index 63aae2858..47fbea1e8 100644 --- a/tests/functional/divi8.asm +++ b/tests/functional/divi8.asm @@ -54,6 +54,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div8.asm" + ; -------------------------------- __DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A diff --git a/tests/functional/divi8a.asm b/tests/functional/divi8a.asm index 195febb06..612afbfa9 100644 --- a/tests/functional/divi8a.asm +++ b/tests/functional/divi8a.asm @@ -33,6 +33,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div8.asm" + ; -------------------------------- __DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A diff --git a/tests/functional/divi8b.asm b/tests/functional/divi8b.asm index eda5776d2..657fb85c6 100644 --- a/tests/functional/divi8b.asm +++ b/tests/functional/divi8b.asm @@ -39,6 +39,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div8.asm" + ; -------------------------------- __DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A diff --git a/tests/functional/divu16.asm b/tests/functional/divu16.asm index 39dd306d1..9465a7048 100644 --- a/tests/functional/divu16.asm +++ b/tests/functional/divu16.asm @@ -55,10 +55,12 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div16.asm" + ; 16 bit division and modulo functions ; for both signed and unsigned values #line 1 "neg16.asm" + ; Negates HL value (16 bit) __ABS16: bit 7, h diff --git a/tests/functional/divu16a.asm b/tests/functional/divu16a.asm index d8437c72f..23e1dee44 100644 --- a/tests/functional/divu16a.asm +++ b/tests/functional/divu16a.asm @@ -33,10 +33,12 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div16.asm" + ; 16 bit division and modulo functions ; for both signed and unsigned values #line 1 "neg16.asm" + ; Negates HL value (16 bit) __ABS16: bit 7, h diff --git a/tests/functional/divu16b.asm b/tests/functional/divu16b.asm index 7ea2cd779..4cfbf8bf6 100644 --- a/tests/functional/divu16b.asm +++ b/tests/functional/divu16b.asm @@ -40,10 +40,12 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div16.asm" + ; 16 bit division and modulo functions ; for both signed and unsigned values #line 1 "neg16.asm" + ; Negates HL value (16 bit) __ABS16: bit 7, h diff --git a/tests/functional/divu32c.asm b/tests/functional/divu32c.asm index ca80e41c5..e02ea30ea 100644 --- a/tests/functional/divu32c.asm +++ b/tests/functional/divu32c.asm @@ -80,7 +80,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div32.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z @@ -254,6 +256,7 @@ __MODI32: ; 32bits signed division modulus #line 71 "divu32c.bas" #line 1 "swap32.asm" + ; Exchanges current DE HL with the ; ones in the stack diff --git a/tests/functional/divu8.asm b/tests/functional/divu8.asm index 15d4ca27c..1a7dad4fb 100644 --- a/tests/functional/divu8.asm +++ b/tests/functional/divu8.asm @@ -54,6 +54,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div8.asm" + ; -------------------------------- __DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A diff --git a/tests/functional/divu8a.asm b/tests/functional/divu8a.asm index 49c5746fb..0229d3f00 100644 --- a/tests/functional/divu8a.asm +++ b/tests/functional/divu8a.asm @@ -33,6 +33,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div8.asm" + ; -------------------------------- __DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A diff --git a/tests/functional/divu8b.asm b/tests/functional/divu8b.asm index a0afff594..a7a965d01 100644 --- a/tests/functional/divu8b.asm +++ b/tests/functional/divu8b.asm @@ -39,6 +39,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div8.asm" + ; -------------------------------- __DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A diff --git a/tests/functional/draw.asm b/tests/functional/draw.asm index 5923eedc0..aa89de316 100644 --- a/tests/functional/draw.asm +++ b/tests/functional/draw.asm @@ -55,6 +55,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "draw.asm" + ; DRAW using bresenhams algorithm and screen positioning ; Copyleft (k) 2010 by J. Rodriguez (a.k.a. Boriel) http://www.boriel.com ; vim:ts=4:et:sw=4: @@ -63,6 +64,7 @@ __CALL_BACK__: ; X parameter in high byte on top of the stack #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -104,7 +106,9 @@ __STOP: ret #line 9 "draw.asm" #line 1 "in_screen.asm" + #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -168,6 +172,7 @@ __OUT_OF_SCREEN_ERR: #line 10 "draw.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -218,6 +223,7 @@ __CLS_SCR: #line 12 "draw.asm" #line 1 "PixelDown.asm" + ; ; PixelDown ; Alvin Albrecht 2002 @@ -262,6 +268,7 @@ SP.PixelDown: ret #line 14 "draw.asm" #line 1 "PixelUp.asm" + ; ; PixelUp ; Alvin Albrecht 2002 @@ -305,6 +312,7 @@ SP.PixelUp: ret #line 15 "draw.asm" #line 1 "PixelLeft.asm" + ; ; PixelLeft ; Jose Rodriguez 2012 @@ -338,6 +346,7 @@ SP.PixelLeft: #line 16 "draw.asm" #line 1 "PixelRight.asm" + ; ; PixelRight ; Jose Rodriguez 2012 @@ -699,7 +708,9 @@ __FASTPLOTEND: #line 46 "draw.bas" #line 1 "ftou32reg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z diff --git a/tests/functional/draw3.asm b/tests/functional/draw3.asm index 66fbfff69..cc76b547e 100644 --- a/tests/functional/draw3.asm +++ b/tests/functional/draw3.asm @@ -85,6 +85,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "draw3.asm" + ; ----------------------------------------------------------- ; vim: et:ts=4:sw=4:ruler: ; @@ -95,6 +96,7 @@ __CALL_BACK__: ; X, and Y parameter in high byte on top of the stack #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -136,6 +138,7 @@ __STOP: ret #line 11 "draw3.asm" #line 1 "plot.asm" + ; MIXED __FASTCAL__ / __CALLE__ PLOT Function ; Plots a point into the screen calling the ZX ROM PLOT routine @@ -144,7 +147,9 @@ __STOP: #line 1 "in_screen.asm" + #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -207,6 +212,7 @@ __OUT_OF_SCREEN_ERR: ENDP #line 9 "plot.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -337,6 +343,7 @@ __PLOT_ERR: ENDP #line 12 "draw3.asm" #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -384,6 +391,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK jp __FPSTACK_PUSH #line 13 "draw3.asm" #line 1 "draw.asm" + ; DRAW using bresenhams algorithm and screen positioning ; Copyleft (k) 2010 by J. Rodriguez (a.k.a. Boriel) http://www.boriel.com ; vim:ts=4:et:sw=4: @@ -397,6 +405,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK #line 1 "PixelDown.asm" + ; ; PixelDown ; Alvin Albrecht 2002 @@ -441,6 +450,7 @@ SP.PixelDown: ret #line 14 "draw.asm" #line 1 "PixelUp.asm" + ; ; PixelUp ; Alvin Albrecht 2002 @@ -484,6 +494,7 @@ SP.PixelUp: ret #line 15 "draw.asm" #line 1 "PixelLeft.asm" + ; ; PixelLeft ; Jose Rodriguez 2012 @@ -517,6 +528,7 @@ SP.PixelLeft: #line 16 "draw.asm" #line 1 "PixelRight.asm" + ; ; PixelRight ; Jose Rodriguez 2012 @@ -1370,7 +1382,9 @@ SUM_B: ENDP #line 76 "draw3.bas" #line 1 "ftou32reg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z diff --git a/tests/functional/einarattr.asm b/tests/functional/einarattr.asm index 1339d1f55..80fdb91d2 100644 --- a/tests/functional/einarattr.asm +++ b/tests/functional/einarattr.asm @@ -58,12 +58,15 @@ __LABEL1: DEFB 41h #line 1 "copy_attr.asm" + #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -97,6 +100,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -147,7 +151,9 @@ __CLS_SCR: #line 7 "print.asm" #line 1 "in_screen.asm" + #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -218,6 +224,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -236,10 +243,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -292,6 +301,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -340,6 +350,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -367,6 +378,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -396,6 +408,7 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register @@ -443,6 +456,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -476,6 +490,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -508,6 +523,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -543,6 +559,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1089,7 +1106,7 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes #line 3 "copy_attr.asm" -#line 4 "/home/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -1148,7 +1165,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/home/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -1168,7 +1185,9 @@ __REFRESH_TMP: + #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1237,6 +1256,7 @@ __REFRESH_TMP: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/einarshift.asm b/tests/functional/einarshift.asm index 329aabbe1..62f00bb45 100644 --- a/tests/functional/einarshift.asm +++ b/tests/functional/einarshift.asm @@ -42,11 +42,13 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -80,6 +82,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -130,7 +133,9 @@ __CLS_SCR: #line 7 "print.asm" #line 1 "in_screen.asm" + #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -201,6 +206,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -219,10 +225,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -275,6 +283,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -323,6 +332,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -350,6 +360,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -379,12 +390,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -443,7 +456,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -501,6 +514,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -534,6 +548,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -566,6 +581,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -601,6 +617,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1148,11 +1165,14 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes #line 32 "einarshift.bas" #line 1 "printu8.asm" + #line 1 "printi8.asm" + #line 1 "printnum.asm" + __PRINTU_START: PROC @@ -1186,6 +1206,7 @@ __PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers #line 2 "printi8.asm" #line 1 "div8.asm" + ; -------------------------------- __DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A diff --git a/tests/functional/elseif3.asm b/tests/functional/elseif3.asm index eae53c51f..5bf6febb6 100644 --- a/tests/functional/elseif3.asm +++ b/tests/functional/elseif3.asm @@ -43,7 +43,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "lti8.asm" + #line 1 "lei8.asm" + __LEI8: ; Signed <= comparison for 8bit int ; A <= H (registers) PROC diff --git a/tests/functional/elseif5.asm b/tests/functional/elseif5.asm index 4ff82f6c2..1f5e8e0b2 100644 --- a/tests/functional/elseif5.asm +++ b/tests/functional/elseif5.asm @@ -47,7 +47,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "lti8.asm" + #line 1 "lei8.asm" + __LEI8: ; Signed <= comparison for 8bit int ; A <= H (registers) PROC diff --git a/tests/functional/elseif6.asm b/tests/functional/elseif6.asm index 50aba929c..14647a71e 100644 --- a/tests/functional/elseif6.asm +++ b/tests/functional/elseif6.asm @@ -36,7 +36,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "lti8.asm" + #line 1 "lei8.asm" + __LEI8: ; Signed <= comparison for 8bit int ; A <= H (registers) PROC diff --git a/tests/functional/emptystrparam.asm b/tests/functional/emptystrparam.asm index 9acb6cee4..537d57c80 100644 --- a/tests/functional/emptystrparam.asm +++ b/tests/functional/emptystrparam.asm @@ -55,6 +55,7 @@ _stringtest__leave: __LABEL0: DEFW 0000h #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -123,6 +124,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -372,7 +374,9 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 43 "emptystrparam.bas" #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -441,6 +445,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -519,9 +524,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl diff --git a/tests/functional/eq0.asm b/tests/functional/eq0.asm index 2bff70a7d..bb0242b94 100644 --- a/tests/functional/eq0.asm +++ b/tests/functional/eq0.asm @@ -34,8 +34,11 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "eqf.asm" + #line 1 "u32tofreg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z @@ -159,6 +162,7 @@ __U32TOFREG_END: #line 1 "ftou32reg.asm" + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) @@ -235,6 +239,7 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A #line 3 "eqf.asm" #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -308,6 +313,7 @@ __EQF: ; A = B #line 25 "eq0.bas" #line 1 "pushf.asm" + ; Routine to push Float pointed by HL ; Into the stack. Notice that the hl points to the last ; byte of the FP number. diff --git a/tests/functional/fastcall0.asm b/tests/functional/fastcall0.asm index 325f8acfb..1d312f1f3 100644 --- a/tests/functional/fastcall0.asm +++ b/tests/functional/fastcall0.asm @@ -65,7 +65,7 @@ _SPFill: call SPPFill_start pop ix ret -#line 1 "PixelUp.asm" +#line 1 "/src/zxb/trunk/library-asm/SP/PixelUp.asm" SP.PixelUp: ld a,h dec h @@ -86,8 +86,8 @@ _SPFill: ld h,a cp $40 ret -#line 31 "Fill.bas" -#line 1 "PixelDown.asm" +#line 31 "/src/zxb/trunk/library/SP/Fill.bas" +#line 1 "/src/zxb/trunk/library-asm/SP/PixelDown.asm" SP.PixelDown: inc h ld a,h @@ -109,8 +109,8 @@ _SPFill: cp $58 ccf ret -#line 32 "Fill.bas" -#line 1 "CharLeft.asm" +#line 32 "/src/zxb/trunk/library/SP/Fill.bas" +#line 1 "/src/zxb/trunk/library-asm/SP/CharLeft.asm" SP.CharLeft: ld a,l dec l @@ -121,8 +121,8 @@ _SPFill: ld h,a cp $40 ret -#line 33 "Fill.bas" -#line 1 "CharRight.asm" +#line 33 "/src/zxb/trunk/library/SP/Fill.bas" +#line 1 "/src/zxb/trunk/library-asm/SP/CharRight.asm" SP.CharRight: inc l ret nz @@ -132,8 +132,8 @@ _SPFill: cp $58 ccf ret -#line 34 "Fill.bas" -#line 1 "GetScrnAddr.asm" +#line 34 "/src/zxb/trunk/library/SP/Fill.bas" +#line 1 "/src/zxb/trunk/library-asm/SP/GetScrnAddr.asm" SPGetScrnAddr: and $07 or $40 @@ -165,7 +165,7 @@ norotate: or l ld e,a ret -#line 35 "Fill.bas" +#line 35 "/src/zxb/trunk/library/SP/Fill.bas" SPPFill_IXBuffer: DEFB 0,0 SPPFill_start: @@ -481,10 +481,12 @@ __LABEL0: DEFW 0001h DEFB 61h #line 1 "circle.asm" + ; Bresenham's like circle algorithm ; best known as Middle Point Circle drawing algorithm #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -526,6 +528,7 @@ __STOP: ret #line 5 "circle.asm" #line 1 "plot.asm" + ; MIXED __FASTCAL__ / __CALLE__ PLOT Function ; Plots a point into the screen calling the ZX ROM PLOT routine @@ -534,7 +537,9 @@ __STOP: #line 1 "in_screen.asm" + #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -597,6 +602,7 @@ __OUT_OF_SCREEN_ERR: ENDP #line 9 "plot.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -937,6 +943,7 @@ __CIRCLE_PLOT: #line 469 "fastcall0.bas" #line 1 "pause.asm" + ; The PAUSE statement (Calling the ROM) __PAUSE: @@ -945,6 +952,7 @@ __PAUSE: jp 1F3Dh ; PAUSE_1 #line 471 "fastcall0.bas" #line 1 "usr_str.asm" + ; This function just returns the address of the UDG of the given str. ; If the str is EMPTY or not a letter, 0 is returned and ERR_NR set ; to "A: Invalid Argument" @@ -954,6 +962,7 @@ __PAUSE: #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -966,6 +975,7 @@ __PAUSE: #line 10 "usr_str.asm" #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1034,6 +1044,7 @@ __PAUSE: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/for0.asm b/tests/functional/for0.asm index 4ce41fea3..ce7e4c631 100644 --- a/tests/functional/for0.asm +++ b/tests/functional/for0.asm @@ -55,6 +55,7 @@ __LABEL5: DEFW 0001h DEFB 20h #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -63,6 +64,7 @@ __LABEL5: ; Our faster implementation #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -136,7 +138,9 @@ __CLS_SCR: #line 42 "for0.bas" #line 1 "lti8.asm" + #line 1 "lei8.asm" + __LEI8: ; Signed <= comparison for 8bit int ; A <= H (registers) PROC @@ -161,8 +165,11 @@ checkParity: #line 2 "lti8.asm" #line 43 "for0.bas" #line 1 "printi8.asm" + #line 1 "printnum.asm" + #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that @@ -171,7 +178,9 @@ checkParity: #line 1 "in_screen.asm" + #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -242,6 +251,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -260,10 +270,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -316,6 +328,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -364,6 +377,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -391,6 +405,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -420,12 +435,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -484,7 +501,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -542,6 +559,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -575,6 +593,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -607,6 +626,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -642,6 +662,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1223,6 +1244,7 @@ __PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers #line 2 "printi8.asm" #line 1 "div8.asm" + ; -------------------------------- __DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A @@ -1352,7 +1374,9 @@ __PRINTU_LOOP: + #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1421,6 +1445,7 @@ __PRINTU_LOOP: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/fporder.asm b/tests/functional/fporder.asm index 9afd4f40d..75f3dcb38 100644 --- a/tests/functional/fporder.asm +++ b/tests/functional/fporder.asm @@ -43,7 +43,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "cos.asm" + #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -104,6 +106,7 @@ COS: ; Computes COS using ROM FP-CALC #line 1 "mulf.asm" + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) ; All of them uses A EDCB registers as 1st paramter. @@ -126,6 +129,7 @@ __MULF: ; Multiplication #line 35 "fporder.bas" #line 1 "pushf.asm" + ; Routine to push Float pointed by HL ; Into the stack. Notice that the hl points to the last ; byte of the FP number. @@ -155,6 +159,7 @@ __FP_PUSH_REV: #line 36 "fporder.bas" #line 1 "storef.asm" + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -187,6 +192,7 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL #line 1 "subf.asm" + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) diff --git a/tests/functional/gef16.asm b/tests/functional/gef16.asm index f62c1fee2..47e878dc4 100644 --- a/tests/functional/gef16.asm +++ b/tests/functional/gef16.asm @@ -93,7 +93,9 @@ __CALL_BACK__: DEFW 0 #line 1 "lti32.asm" + #line 1 "sub32.asm" + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) @@ -147,6 +149,7 @@ checkParity: ENDP #line 83 "gef16.bas" #line 1 "swap32.asm" + ; Exchanges current DE HL with the ; ones in the stack diff --git a/tests/functional/gei32.asm b/tests/functional/gei32.asm index 6d1bc8a5d..613251151 100644 --- a/tests/functional/gei32.asm +++ b/tests/functional/gei32.asm @@ -108,7 +108,9 @@ __CALL_BACK__: DEFW 0 #line 1 "lti32.asm" + #line 1 "sub32.asm" + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) @@ -162,6 +164,7 @@ checkParity: ENDP #line 98 "gei32.bas" #line 1 "swap32.asm" + ; Exchanges current DE HL with the ; ones in the stack diff --git a/tests/functional/gei8.asm b/tests/functional/gei8.asm index cf7a0a31c..50f405ca2 100644 --- a/tests/functional/gei8.asm +++ b/tests/functional/gei8.asm @@ -35,6 +35,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "lei8.asm" + __LEI8: ; Signed <= comparison for 8bit int ; A <= H (registers) PROC diff --git a/tests/functional/geu32.asm b/tests/functional/geu32.asm index f4f8e55dc..02d3214b2 100644 --- a/tests/functional/geu32.asm +++ b/tests/functional/geu32.asm @@ -107,6 +107,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sub32.asm" + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) @@ -136,6 +137,7 @@ __SUB32: ret #line 98 "geu32.bas" #line 1 "swap32.asm" + ; Exchanges current DE HL with the ; ones in the stack diff --git a/tests/functional/gtf16.asm b/tests/functional/gtf16.asm index e1926a5be..53c88ffef 100644 --- a/tests/functional/gtf16.asm +++ b/tests/functional/gtf16.asm @@ -93,7 +93,9 @@ __CALL_BACK__: DEFW 0 #line 1 "lei32.asm" + #line 1 "sub32.asm" + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) @@ -156,6 +158,7 @@ checkParity: ENDP #line 83 "gtf16.bas" #line 1 "swap32.asm" + ; Exchanges current DE HL with the ; ones in the stack diff --git a/tests/functional/gti32.asm b/tests/functional/gti32.asm index ec7cdd0bc..c81ba6b93 100644 --- a/tests/functional/gti32.asm +++ b/tests/functional/gti32.asm @@ -108,7 +108,9 @@ __CALL_BACK__: DEFW 0 #line 1 "lei32.asm" + #line 1 "sub32.asm" + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) @@ -171,6 +173,7 @@ checkParity: ENDP #line 98 "gti32.bas" #line 1 "swap32.asm" + ; Exchanges current DE HL with the ; ones in the stack diff --git a/tests/functional/gti8.asm b/tests/functional/gti8.asm index 184445214..27cc14d43 100644 --- a/tests/functional/gti8.asm +++ b/tests/functional/gti8.asm @@ -36,7 +36,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "lti8.asm" + #line 1 "lei8.asm" + __LEI8: ; Signed <= comparison for 8bit int ; A <= H (registers) PROC diff --git a/tests/functional/gtu32.asm b/tests/functional/gtu32.asm index dc51fa162..3ce19ea08 100644 --- a/tests/functional/gtu32.asm +++ b/tests/functional/gtu32.asm @@ -127,6 +127,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "swap32.asm" + ; Exchanges current DE HL with the ; ones in the stack diff --git a/tests/functional/ifelse1.asm b/tests/functional/ifelse1.asm index 80d48f03b..12147cacd 100644 --- a/tests/functional/ifelse1.asm +++ b/tests/functional/ifelse1.asm @@ -57,11 +57,13 @@ __LABEL2: DEFB 6Eh DEFB 21h #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -95,6 +97,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -145,7 +148,9 @@ __CLS_SCR: #line 7 "print.asm" #line 1 "in_screen.asm" + #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -216,6 +221,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -234,10 +240,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -290,6 +298,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -338,6 +347,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -365,6 +375,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -394,12 +405,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -458,7 +471,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -516,6 +529,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -549,6 +563,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -581,6 +596,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -616,6 +632,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1166,7 +1183,9 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes + #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1235,6 +1254,7 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/ifthen.asm b/tests/functional/ifthen.asm index 7ec2148da..dde663935 100644 --- a/tests/functional/ifthen.asm +++ b/tests/functional/ifthen.asm @@ -49,7 +49,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "lti8.asm" + #line 1 "lei8.asm" + __LEI8: ; Signed <= comparison for 8bit int ; A <= H (registers) PROC diff --git a/tests/functional/ifthenelse.asm b/tests/functional/ifthenelse.asm index d425548fe..f3268e58e 100644 --- a/tests/functional/ifthenelse.asm +++ b/tests/functional/ifthenelse.asm @@ -57,7 +57,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "lti8.asm" + #line 1 "lei8.asm" + __LEI8: ; Signed <= comparison for 8bit int ; A <= H (registers) PROC diff --git a/tests/functional/ifthenelseif.asm b/tests/functional/ifthenelseif.asm index b01764853..b8e3c1ec9 100644 --- a/tests/functional/ifthenelseif.asm +++ b/tests/functional/ifthenelseif.asm @@ -126,7 +126,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "lti8.asm" + #line 1 "lei8.asm" + __LEI8: ; Signed <= comparison for 8bit int ; A <= H (registers) PROC diff --git a/tests/functional/inkey.asm b/tests/functional/inkey.asm index 1f8e5c285..376a7566b 100644 --- a/tests/functional/inkey.asm +++ b/tests/functional/inkey.asm @@ -43,12 +43,14 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "inkey.asm" + ; INKEY Function ; Returns a string allocated in dynamic memory ; containing the string. ; An empty string otherwise. #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -117,6 +119,7 @@ __CALL_BACK__: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -158,6 +161,7 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -321,9 +325,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -455,11 +459,13 @@ __EMPTY_INKEY: #line 30 "inkey.bas" #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -493,6 +499,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -545,6 +552,7 @@ __CLS_SCR: + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) @@ -574,6 +582,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -592,10 +601,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -648,6 +659,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -696,6 +708,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -723,6 +736,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -752,12 +766,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -816,7 +832,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -874,6 +890,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -907,6 +924,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -939,6 +957,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -974,6 +993,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1521,6 +1541,7 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes #line 31 "inkey.bas" #line 1 "print_eol_attr.asm" + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes @@ -1535,7 +1556,9 @@ PRINT_EOL_ATTR: + #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1780,6 +1803,7 @@ __PRINT_STR: #line 33 "inkey.bas" #line 1 "storestr2.asm" + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication diff --git a/tests/functional/inktemp.asm b/tests/functional/inktemp.asm index 897d617ab..11621705a 100644 --- a/tests/functional/inktemp.asm +++ b/tests/functional/inktemp.asm @@ -52,10 +52,12 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "circle.asm" + ; Bresenham's like circle algorithm ; best known as Middle Point Circle drawing algorithm #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -97,6 +99,7 @@ __STOP: ret #line 5 "circle.asm" #line 1 "plot.asm" + ; MIXED __FASTCAL__ / __CALLE__ PLOT Function ; Plots a point into the screen calling the ZX ROM PLOT routine @@ -105,7 +108,9 @@ __STOP: #line 1 "in_screen.asm" + #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -168,6 +173,7 @@ __OUT_OF_SCREEN_ERR: ENDP #line 9 "plot.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -507,9 +513,11 @@ __CIRCLE_PLOT: ENDP #line 43 "inktemp.bas" #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -544,9 +552,9 @@ COPY_ATTR: __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) -#line 63 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 63 "/src/zxb/trunk/library-asm/copy_attr.asm" ret -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -561,6 +569,7 @@ __REFRESH_TMP: #line 44 "inktemp.bas" #line 1 "draw.asm" + ; DRAW using bresenhams algorithm and screen positioning ; Copyleft (k) 2010 by J. Rodriguez (a.k.a. Boriel) http://www.boriel.com ; vim:ts=4:et:sw=4: @@ -574,6 +583,7 @@ __REFRESH_TMP: #line 1 "PixelDown.asm" + ; ; PixelDown ; Alvin Albrecht 2002 @@ -618,6 +628,7 @@ SP.PixelDown: ret #line 14 "draw.asm" #line 1 "PixelUp.asm" + ; ; PixelUp ; Alvin Albrecht 2002 @@ -661,6 +672,7 @@ SP.PixelUp: ret #line 15 "draw.asm" #line 1 "PixelLeft.asm" + ; ; PixelLeft ; Jose Rodriguez 2012 @@ -694,6 +706,7 @@ SP.PixelLeft: #line 16 "draw.asm" #line 1 "PixelRight.asm" + ; ; PixelRight ; Jose Rodriguez 2012 @@ -1055,6 +1068,7 @@ __FASTPLOTEND: #line 45 "inktemp.bas" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -1082,6 +1096,7 @@ FLASH_TMP: #line 46 "inktemp.bas" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register @@ -1127,6 +1142,7 @@ INK_TMP: #line 47 "inktemp.bas" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register @@ -1174,6 +1190,7 @@ OVER_TMP: #line 48 "inktemp.bas" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register diff --git a/tests/functional/lcd3.asm b/tests/functional/lcd3.asm index 24c3b79ff..0d88dc9dd 100644 --- a/tests/functional/lcd3.asm +++ b/tests/functional/lcd3.asm @@ -154,7 +154,9 @@ __LABEL2: DEFB 4Fh DEFB 46h #line 1 "addf.asm" + #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -223,6 +225,7 @@ __ADDF: ; Addition #line 141 "lcd3.bas" #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -291,6 +294,7 @@ __ADDF: ; Addition ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -540,7 +544,9 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 142 "lcd3.bas" #line 1 "ftou32reg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z @@ -649,7 +655,9 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A #line 143 "lcd3.bas" #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -718,6 +726,7 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -796,9 +805,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -918,11 +927,13 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 144 "lcd3.bas" #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -956,6 +967,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -1008,6 +1020,7 @@ __CLS_SCR: + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) @@ -1037,6 +1050,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -1055,10 +1069,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -1111,6 +1127,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -1159,6 +1176,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -1186,6 +1204,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -1215,12 +1234,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -1279,7 +1300,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -1337,6 +1358,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -1370,6 +1392,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -1402,6 +1425,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -1437,6 +1461,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1989,6 +2014,7 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes + ; PRINT command routine ; Prints string pointed by HL @@ -2042,6 +2068,7 @@ __PRINT_STR: #line 146 "lcd3.bas" #line 1 "pstorestr2.asm" + ; vim:ts=4:et:sw=4 ; ; Stores an string (pointer to the HEAP by DE) into the address pointed @@ -2050,6 +2077,7 @@ __PRINT_STR: ; #line 1 "storestr2.asm" + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication @@ -2100,6 +2128,7 @@ __PSTORE_STR2: #line 147 "lcd3.bas" #line 1 "pushf.asm" + ; Routine to push Float pointed by HL ; Into the stack. Notice that the hl points to the last ; byte of the FP number. @@ -2129,6 +2158,7 @@ __FP_PUSH_REV: #line 148 "lcd3.bas" #line 1 "str.asm" + ; The STR$( ) BASIC function implementation ; Given a FP number in C ED LH @@ -2209,7 +2239,9 @@ __STR_END: #line 149 "lcd3.bas" #line 1 "strcat.asm" + #line 1 "strlen.asm" + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL @@ -2355,6 +2387,7 @@ __STRCATEND: #line 1 "u32tofreg.asm" + __I8TOFREG: ld l, a rlca diff --git a/tests/functional/lcd7.asm b/tests/functional/lcd7.asm index 36c1441a7..a68874f21 100644 --- a/tests/functional/lcd7.asm +++ b/tests/functional/lcd7.asm @@ -85,6 +85,7 @@ __LABEL0: DEFB 4Fh DEFB 4Bh #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -153,6 +154,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -402,7 +404,9 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 72 "lcd7.bas" #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -471,6 +475,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -549,9 +554,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -671,15 +676,18 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 73 "lcd7.bas" #line 1 "print_eol_attr.asm" + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -713,6 +721,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -765,6 +774,7 @@ __CLS_SCR: + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) @@ -794,6 +804,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -812,10 +823,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -868,6 +881,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -916,6 +930,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -943,6 +958,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -972,12 +988,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -1036,7 +1054,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -1094,6 +1112,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -1127,6 +1146,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -1159,6 +1179,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -1194,6 +1215,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1752,6 +1774,7 @@ PRINT_EOL_ATTR: + ; PRINT command routine ; Prints string pointed by HL @@ -1805,6 +1828,7 @@ __PRINT_STR: #line 75 "lcd7.bas" #line 1 "pstorestr.asm" + ; vim:ts=4:et:sw=4 ; ; Stores an string (pointer to the HEAP by DE) into the address pointed @@ -1812,6 +1836,7 @@ __PRINT_STR: ; #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -1825,7 +1850,9 @@ __PRINT_STR: #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/lcd8.asm b/tests/functional/lcd8.asm index dfde6ad6b..2a43a3492 100644 --- a/tests/functional/lcd8.asm +++ b/tests/functional/lcd8.asm @@ -87,6 +87,7 @@ __LABEL0: DEFB 4Fh DEFB 4Bh #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -155,6 +156,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -404,7 +406,9 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 74 "lcd8.bas" #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -473,6 +477,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -551,9 +556,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -673,15 +678,18 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 75 "lcd8.bas" #line 1 "print_eol_attr.asm" + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -715,6 +723,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -767,6 +776,7 @@ __CLS_SCR: + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) @@ -796,6 +806,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -814,10 +825,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -870,6 +883,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -918,6 +932,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -945,6 +960,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -974,12 +990,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -1038,7 +1056,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -1096,6 +1114,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -1129,6 +1148,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -1161,6 +1181,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -1196,6 +1217,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1754,6 +1776,7 @@ PRINT_EOL_ATTR: + ; PRINT command routine ; Prints string pointed by HL diff --git a/tests/functional/lcd9.asm b/tests/functional/lcd9.asm index 2ec1ca09f..cb3601baa 100644 --- a/tests/functional/lcd9.asm +++ b/tests/functional/lcd9.asm @@ -75,6 +75,7 @@ __LABEL0: DEFB 4Fh DEFB 4Bh #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -143,6 +144,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -392,7 +394,9 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 62 "lcd9.bas" #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -461,6 +465,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -539,9 +544,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -661,15 +666,18 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 63 "lcd9.bas" #line 1 "print_eol_attr.asm" + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -703,6 +711,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -755,6 +764,7 @@ __CLS_SCR: + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) @@ -784,6 +794,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -802,10 +813,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -858,6 +871,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -906,6 +920,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -933,6 +948,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -962,12 +978,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -1026,7 +1044,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -1084,6 +1102,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -1117,6 +1136,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -1149,6 +1169,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -1184,6 +1205,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1742,6 +1764,7 @@ PRINT_EOL_ATTR: + ; PRINT command routine ; Prints string pointed by HL @@ -1795,6 +1818,7 @@ __PRINT_STR: #line 65 "lcd9.bas" #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -1808,7 +1832,9 @@ __PRINT_STR: #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/lef16.asm b/tests/functional/lef16.asm index a532a0a3e..9e0b7d417 100644 --- a/tests/functional/lef16.asm +++ b/tests/functional/lef16.asm @@ -85,7 +85,9 @@ __CALL_BACK__: DEFW 0 #line 1 "lei32.asm" + #line 1 "sub32.asm" + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) @@ -148,6 +150,7 @@ checkParity: ENDP #line 75 "lef16.bas" #line 1 "swap32.asm" + ; Exchanges current DE HL with the ; ones in the stack diff --git a/tests/functional/lei32.asm b/tests/functional/lei32.asm index a6efbc0be..8b5e0dc73 100644 --- a/tests/functional/lei32.asm +++ b/tests/functional/lei32.asm @@ -98,7 +98,9 @@ __CALL_BACK__: DEFW 0 #line 1 "lei32.asm" + #line 1 "sub32.asm" + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) @@ -161,6 +163,7 @@ checkParity: ENDP #line 88 "lei32.bas" #line 1 "swap32.asm" + ; Exchanges current DE HL with the ; ones in the stack diff --git a/tests/functional/leu32.asm b/tests/functional/leu32.asm index a4d294075..d995b7356 100644 --- a/tests/functional/leu32.asm +++ b/tests/functional/leu32.asm @@ -132,6 +132,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "swap32.asm" + ; Exchanges current DE HL with the ; ones in the stack diff --git a/tests/functional/load02.asm b/tests/functional/load02.asm index 415de1175..32e3db575 100644 --- a/tests/functional/load02.asm +++ b/tests/functional/load02.asm @@ -48,7 +48,9 @@ __LABEL0: DEFB 74h DEFB 31h #line 1 "load.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -117,6 +119,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -158,6 +161,7 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -321,9 +325,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -400,6 +404,7 @@ __MEM_SUBTRACT: #line 2 "load.asm" #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -591,11 +596,13 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 3 "load.asm" #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -629,6 +636,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -681,6 +689,7 @@ __CLS_SCR: + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) @@ -710,6 +719,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -728,10 +738,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -784,6 +796,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -832,6 +845,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -859,6 +873,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -888,10 +903,12 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -917,9 +934,9 @@ COPY_ATTR: __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) -#line 63 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 63 "/src/zxb/trunk/library-asm/copy_attr.asm" ret -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -977,6 +994,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -1010,6 +1028,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -1042,6 +1061,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -1077,6 +1097,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1905,6 +1926,7 @@ PRINT_TAPE_MSG: #line 1 "loadstr.asm" + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL diff --git a/tests/functional/load03.asm b/tests/functional/load03.asm index ecd56d9bb..631719d45 100644 --- a/tests/functional/load03.asm +++ b/tests/functional/load03.asm @@ -47,7 +47,9 @@ __LABEL0: DEFB 73h DEFB 74h #line 1 "load.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -116,6 +118,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -157,6 +160,7 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -320,9 +324,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -399,6 +403,7 @@ __MEM_SUBTRACT: #line 2 "load.asm" #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -590,11 +595,13 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 3 "load.asm" #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -628,6 +635,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -680,6 +688,7 @@ __CLS_SCR: + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) @@ -709,6 +718,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -727,10 +737,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -783,6 +795,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -831,6 +844,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -858,6 +872,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -887,10 +902,12 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -916,9 +933,9 @@ COPY_ATTR: __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) -#line 63 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 63 "/src/zxb/trunk/library-asm/copy_attr.asm" ret -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -976,6 +993,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -1009,6 +1027,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -1041,6 +1060,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -1076,6 +1096,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1904,6 +1925,7 @@ PRINT_TAPE_MSG: #line 1 "loadstr.asm" + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL diff --git a/tests/functional/loadstr.asm b/tests/functional/loadstr.asm index 23e066ea1..653869dd2 100644 --- a/tests/functional/loadstr.asm +++ b/tests/functional/loadstr.asm @@ -44,6 +44,7 @@ __LABEL0: DEFB 31h DEFB 30h #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -57,7 +58,9 @@ __LABEL0: #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -127,6 +130,7 @@ __LABEL0: #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -168,6 +172,7 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -237,6 +242,7 @@ __STOP: #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -400,9 +406,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -479,6 +485,7 @@ __MEM_SUBTRACT: #line 71 "realloc.asm" #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -886,6 +893,7 @@ __STORE_STR: #line 32 "loadstr.bas" #line 1 "storestr2.asm" + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication @@ -927,6 +935,7 @@ __STORE_STR2: #line 33 "loadstr.bas" #line 1 "str.asm" + ; The STR$( ) BASIC function implementation ; Given a FP number in C ED LH @@ -935,6 +944,7 @@ __STORE_STR2: #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -982,6 +992,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK jp __FPSTACK_PUSH #line 9 "str.asm" #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -1067,6 +1078,7 @@ __STR_END: + VAL: ; Computes VAL(a$) using ROM FP-CALC ; HL = address of a$ ; Returns FP number in C ED LH registers diff --git a/tests/functional/loadu16ii.asm b/tests/functional/loadu16ii.asm index 6e3eb2d35..c07dc8a27 100644 --- a/tests/functional/loadu16ii.asm +++ b/tests/functional/loadu16ii.asm @@ -53,6 +53,7 @@ __LABEL__test: ld c, l jp __END_PROGRAM #line 1 "mul16.asm" + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned @@ -108,11 +109,13 @@ __MUL16NOADD: #line 43 "loadu16ii.bas" #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -146,6 +149,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -196,7 +200,9 @@ __CLS_SCR: #line 7 "print.asm" #line 1 "in_screen.asm" + #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -267,6 +273,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -285,10 +292,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -341,6 +350,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -389,6 +399,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -416,6 +427,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -445,12 +457,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -509,7 +523,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -567,6 +581,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -600,6 +615,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -632,6 +648,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -667,6 +684,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1214,11 +1232,14 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes #line 44 "loadu16ii.bas" #line 1 "printu16.asm" + #line 1 "printi16.asm" + #line 1 "printnum.asm" + __PRINTU_START: PROC @@ -1252,10 +1273,12 @@ __PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers #line 2 "printi16.asm" #line 1 "div16.asm" + ; 16 bit division and modulo functions ; for both signed and unsigned values #line 1 "neg16.asm" + ; Negates HL value (16 bit) __ABS16: bit 7, h diff --git a/tests/functional/ltee1.asm b/tests/functional/ltee1.asm index cbd832bdc..8d0983b37 100644 --- a/tests/functional/ltee1.asm +++ b/tests/functional/ltee1.asm @@ -101,6 +101,7 @@ __LABEL1: DEFB 6Ch DEFB 65h #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -169,6 +170,7 @@ __LABEL1: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -418,7 +420,9 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 88 "ltee1.bas" #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -487,6 +491,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -565,9 +570,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -687,15 +692,18 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 89 "ltee1.bas" #line 1 "print_eol_attr.asm" + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -729,6 +737,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -781,6 +790,7 @@ __CLS_SCR: + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) @@ -810,6 +820,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -828,10 +839,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -884,6 +897,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -932,6 +946,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -959,6 +974,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -988,12 +1004,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -1052,7 +1070,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -1110,6 +1128,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -1143,6 +1162,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -1175,6 +1195,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -1210,6 +1231,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1768,6 +1790,7 @@ PRINT_EOL_ATTR: + ; PRINT command routine ; Prints string pointed by HL @@ -1821,6 +1844,7 @@ __PRINT_STR: #line 91 "ltee1.bas" #line 1 "pstorestr.asm" + ; vim:ts=4:et:sw=4 ; ; Stores an string (pointer to the HEAP by DE) into the address pointed @@ -1828,6 +1852,7 @@ __PRINT_STR: ; #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -1841,7 +1866,9 @@ __PRINT_STR: #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -2138,6 +2165,7 @@ __PSTORE_STR: #line 92 "ltee1.bas" #line 1 "pstorestr2.asm" + ; vim:ts=4:et:sw=4 ; ; Stores an string (pointer to the HEAP by DE) into the address pointed @@ -2146,6 +2174,7 @@ __PSTORE_STR: ; #line 1 "storestr2.asm" + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication @@ -2197,7 +2226,9 @@ __PSTORE_STR2: #line 1 "strcat.asm" + #line 1 "strlen.asm" + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL diff --git a/tests/functional/ltee3.asm b/tests/functional/ltee3.asm index 97dcb45c7..0fc061c74 100644 --- a/tests/functional/ltee3.asm +++ b/tests/functional/ltee3.asm @@ -63,6 +63,7 @@ __LABEL0: DEFB 6Eh DEFB 67h #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -131,6 +132,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -380,7 +382,9 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 51 "ltee3.bas" #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -449,6 +453,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -527,9 +532,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl diff --git a/tests/functional/ltee5.asm b/tests/functional/ltee5.asm index 439d77e5a..052c83ab4 100644 --- a/tests/functional/ltee5.asm +++ b/tests/functional/ltee5.asm @@ -74,6 +74,7 @@ __LABEL1: DEFB 61h DEFB 6Ch #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -142,6 +143,7 @@ __LABEL1: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -391,6 +393,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 62 "ltee5.bas" #line 1 "pstorestr.asm" + ; vim:ts=4:et:sw=4 ; ; Stores an string (pointer to the HEAP by DE) into the address pointed @@ -398,6 +401,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -411,7 +415,9 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -481,6 +487,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -522,6 +529,7 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -628,9 +636,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl diff --git a/tests/functional/ltee6.asm b/tests/functional/ltee6.asm index 47a96d7f7..0888daed1 100644 --- a/tests/functional/ltee6.asm +++ b/tests/functional/ltee6.asm @@ -46,6 +46,7 @@ __LABEL0: DEFB 61h DEFB 6Ch #line 1 "array.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -65,6 +66,7 @@ __LABEL0: #line 1 "mul16.asm" + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned @@ -120,7 +122,7 @@ __MUL16NOADD: #line 20 "array.asm" -#line 24 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 24 "/src/zxb/trunk/library-asm/array.asm" __ARRAY: PROC @@ -142,12 +144,12 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 48 "/src/zxb/trunk/library-asm/array.asm" LOOP: pop bc ; Get next index (Ai) from the stack -#line 60 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 60 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -165,10 +167,10 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -179,7 +181,7 @@ ARRAY_END: push de exx -#line 100 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -210,7 +212,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 131 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start @@ -247,6 +249,7 @@ __FNMUL2: #line 34 "ltee6.bas" #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -260,7 +263,9 @@ __FNMUL2: #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -330,6 +335,7 @@ __FNMUL2: #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -371,6 +377,7 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -440,6 +447,7 @@ __STOP: #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -603,9 +611,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -682,6 +690,7 @@ __MEM_SUBTRACT: #line 71 "realloc.asm" #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/ltee7.asm b/tests/functional/ltee7.asm index a2dcfaacd..01786c658 100644 --- a/tests/functional/ltee7.asm +++ b/tests/functional/ltee7.asm @@ -84,6 +84,7 @@ __LABEL0: DEFB 6Ch DEFB 6Fh #line 1 "array.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -103,6 +104,7 @@ __LABEL0: #line 1 "mul16.asm" + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned @@ -158,7 +160,7 @@ __MUL16NOADD: #line 20 "array.asm" -#line 24 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 24 "/src/zxb/trunk/library-asm/array.asm" __ARRAY: PROC @@ -180,12 +182,12 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 48 "/src/zxb/trunk/library-asm/array.asm" LOOP: pop bc ; Get next index (Ai) from the stack -#line 60 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 60 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -203,10 +205,10 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -217,7 +219,7 @@ ARRAY_END: push de exx -#line 100 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -248,7 +250,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/Users/boriel/Documents/src/zxbasic/library-asm/array.asm" +#line 131 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start @@ -285,11 +287,13 @@ __FNMUL2: #line 72 "ltee7.bas" #line 1 "arrayfree.asm" + ; This routine is in charge of freeing an array of strings from memory ; HL = Pointer to start of array in memory ; Top of the stack = Number of elements of the array #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -358,6 +362,7 @@ __FNMUL2: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -672,6 +677,7 @@ __ARRAY_FREE_MEM: ; like the above, buf also frees the array itself #line 73 "ltee7.bas" #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -685,7 +691,9 @@ __ARRAY_FREE_MEM: ; like the above, buf also frees the array itself #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -755,6 +763,7 @@ __ARRAY_FREE_MEM: ; like the above, buf also frees the array itself #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -796,6 +805,7 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -902,9 +912,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl diff --git a/tests/functional/ltee9.asm b/tests/functional/ltee9.asm index 140138bed..adb919f96 100644 --- a/tests/functional/ltee9.asm +++ b/tests/functional/ltee9.asm @@ -94,10 +94,12 @@ _start__leave: pop ix ret #line 1 "div16.asm" + ; 16 bit division and modulo functions ; for both signed and unsigned values #line 1 "neg16.asm" + ; Negates HL value (16 bit) __ABS16: bit 7, h @@ -213,8 +215,10 @@ __MODI16: ; 16 bit modulus #line 85 "ltee9.bas" #line 1 "mul32.asm" + #line 1 "_mul32.asm" + ; Ripped from: http://www.andreadrian.de/oldcpu/z80_number_cruncher.html#moztocid784223 ; Used with permission. ; Multiplies 32x32 bit integer (DEHL x D'E'H'L') @@ -304,7 +308,9 @@ __TO32BIT: ; Converts H'L'HLB'C'AC to DEHL (Discards H'L'HL) #line 86 "ltee9.bas" #line 1 "pstore32.asm" + #line 1 "store32.asm" + __PISTORE32: push hl push ix @@ -340,6 +346,7 @@ __PSTORE32: jp __STORE32 #line 87 "ltee9.bas" #line 1 "sub32.asm" + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) diff --git a/tests/functional/ltf16.asm b/tests/functional/ltf16.asm index d7ff1b1ea..171491c3c 100644 --- a/tests/functional/ltf16.asm +++ b/tests/functional/ltf16.asm @@ -85,7 +85,9 @@ __CALL_BACK__: DEFW 0 #line 1 "lti32.asm" + #line 1 "sub32.asm" + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) @@ -139,6 +141,7 @@ checkParity: ENDP #line 75 "ltf16.bas" #line 1 "swap32.asm" + ; Exchanges current DE HL with the ; ones in the stack diff --git a/tests/functional/lti32c.asm b/tests/functional/lti32c.asm index 60159b495..e3906c743 100644 --- a/tests/functional/lti32c.asm +++ b/tests/functional/lti32c.asm @@ -98,7 +98,9 @@ __CALL_BACK__: DEFW 0 #line 1 "lti32.asm" + #line 1 "sub32.asm" + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) @@ -152,6 +154,7 @@ checkParity: ENDP #line 88 "lti32c.bas" #line 1 "swap32.asm" + ; Exchanges current DE HL with the ; ones in the stack diff --git a/tests/functional/ltu32c.asm b/tests/functional/ltu32c.asm index d723cc686..564f08585 100644 --- a/tests/functional/ltu32c.asm +++ b/tests/functional/ltu32c.asm @@ -102,6 +102,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sub32.asm" + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) @@ -131,6 +132,7 @@ __SUB32: ret #line 93 "ltu32c.bas" #line 1 "swap32.asm" + ; Exchanges current DE HL with the ; ones in the stack diff --git a/tests/functional/mcleod.asm b/tests/functional/mcleod.asm index 7e4bc568c..4b9ab25a8 100644 --- a/tests/functional/mcleod.asm +++ b/tests/functional/mcleod.asm @@ -38,7 +38,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "ftou32reg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z @@ -147,7 +149,9 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A #line 29 "mcleod.bas" #line 1 "mulf.asm" + #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -216,6 +220,7 @@ __MULF: ; Multiplication #line 30 "mcleod.bas" #line 1 "random.asm" + ; RANDOM functions RANDOMIZE: diff --git a/tests/functional/mcleod2.asm b/tests/functional/mcleod2.asm index c88bfdc77..d2fd41b24 100644 --- a/tests/functional/mcleod2.asm +++ b/tests/functional/mcleod2.asm @@ -35,6 +35,7 @@ __CALL_BACK__: __LABEL0: DEFW 0000h #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -48,7 +49,9 @@ __LABEL0: #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -118,6 +121,7 @@ __LABEL0: #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -159,6 +163,7 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -228,6 +233,7 @@ __STOP: #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -391,9 +397,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -470,6 +476,7 @@ __MEM_SUBTRACT: #line 71 "realloc.asm" #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/modf16c.asm b/tests/functional/modf16c.asm index 4c3194f7a..75c10937d 100644 --- a/tests/functional/modf16c.asm +++ b/tests/functional/modf16c.asm @@ -77,11 +77,15 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "modf16.asm" + ; Computes A % B for fixed values #line 1 "divf16.asm" + #line 1 "div32.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z @@ -339,8 +343,10 @@ __ENDF16DIV: ; Put the sign on the result #line 4 "modf16.asm" #line 1 "mulf16.asm" + #line 1 "_mul32.asm" + ; Ripped from: http://www.andreadrian.de/oldcpu/z80_number_cruncher.html#moztocid784223 ; Used with permission. ; Multiplies 32x32 bit integer (DEHL x D'E'H'L') @@ -483,6 +489,7 @@ __MODF16: #line 68 "modf16c.bas" #line 1 "swap32.asm" + ; Exchanges current DE HL with the ; ones in the stack diff --git a/tests/functional/modi32c.asm b/tests/functional/modi32c.asm index 85145cb7e..17478b430 100644 --- a/tests/functional/modi32c.asm +++ b/tests/functional/modi32c.asm @@ -80,7 +80,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div32.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z @@ -254,6 +256,7 @@ __MODI32: ; 32bits signed division modulus #line 71 "modi32c.bas" #line 1 "swap32.asm" + ; Exchanges current DE HL with the ; ones in the stack diff --git a/tests/functional/modi8.asm b/tests/functional/modi8.asm index 03b2b7b26..82f98a1e9 100644 --- a/tests/functional/modi8.asm +++ b/tests/functional/modi8.asm @@ -53,6 +53,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div8.asm" + ; -------------------------------- __DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A diff --git a/tests/functional/modi8a.asm b/tests/functional/modi8a.asm index 1847ccade..d7b577c98 100644 --- a/tests/functional/modi8a.asm +++ b/tests/functional/modi8a.asm @@ -33,6 +33,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div8.asm" + ; -------------------------------- __DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A diff --git a/tests/functional/modi8b.asm b/tests/functional/modi8b.asm index 0b08920db..c30eeef68 100644 --- a/tests/functional/modi8b.asm +++ b/tests/functional/modi8b.asm @@ -39,6 +39,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div8.asm" + ; -------------------------------- __DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A diff --git a/tests/functional/modu32c.asm b/tests/functional/modu32c.asm index 1e6dd02a6..40fa4a6ac 100644 --- a/tests/functional/modu32c.asm +++ b/tests/functional/modu32c.asm @@ -80,7 +80,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div32.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z @@ -254,6 +256,7 @@ __MODI32: ; 32bits signed division modulus #line 71 "modu32c.bas" #line 1 "swap32.asm" + ; Exchanges current DE HL with the ; ones in the stack diff --git a/tests/functional/modu8.asm b/tests/functional/modu8.asm index 6ec5f3e6f..bce638da9 100644 --- a/tests/functional/modu8.asm +++ b/tests/functional/modu8.asm @@ -53,6 +53,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div8.asm" + ; -------------------------------- __DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A diff --git a/tests/functional/modu8a.asm b/tests/functional/modu8a.asm index fc0766aec..8c977e225 100644 --- a/tests/functional/modu8a.asm +++ b/tests/functional/modu8a.asm @@ -33,6 +33,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div8.asm" + ; -------------------------------- __DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A diff --git a/tests/functional/modu8b.asm b/tests/functional/modu8b.asm index 73aca2a7f..840936ba6 100644 --- a/tests/functional/modu8b.asm +++ b/tests/functional/modu8b.asm @@ -39,6 +39,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div8.asm" + ; -------------------------------- __DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A diff --git a/tests/functional/mul16.asm b/tests/functional/mul16.asm index 44e77d986..6cf21e992 100644 --- a/tests/functional/mul16.asm +++ b/tests/functional/mul16.asm @@ -39,6 +39,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "mul16.asm" + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned diff --git a/tests/functional/mul16a.asm b/tests/functional/mul16a.asm index 41c625f7f..6abc4feac 100644 --- a/tests/functional/mul16a.asm +++ b/tests/functional/mul16a.asm @@ -34,6 +34,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "mul16.asm" + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned diff --git a/tests/functional/mul16b.asm b/tests/functional/mul16b.asm index ee4e0c06d..fb8c5c1d0 100644 --- a/tests/functional/mul16b.asm +++ b/tests/functional/mul16b.asm @@ -40,6 +40,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "mul16.asm" + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned diff --git a/tests/functional/mul8.asm b/tests/functional/mul8.asm index 333507d9b..b76fc3344 100644 --- a/tests/functional/mul8.asm +++ b/tests/functional/mul8.asm @@ -55,6 +55,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "mul8.asm" + __MUL8: ; Performs 8bit x 8bit multiplication PROC diff --git a/tests/functional/mul8a.asm b/tests/functional/mul8a.asm index 2afb00062..3d1bbfb3a 100644 --- a/tests/functional/mul8a.asm +++ b/tests/functional/mul8a.asm @@ -34,6 +34,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "mul8.asm" + __MUL8: ; Performs 8bit x 8bit multiplication PROC diff --git a/tests/functional/mul8b.asm b/tests/functional/mul8b.asm index 60a3cd94f..8bbe2ee80 100644 --- a/tests/functional/mul8b.asm +++ b/tests/functional/mul8b.asm @@ -40,6 +40,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "mul8.asm" + __MUL8: ; Performs 8bit x 8bit multiplication PROC diff --git a/tests/functional/mulf00.asm b/tests/functional/mulf00.asm index 5b15bd0f8..47ac6b8af 100644 --- a/tests/functional/mulf00.asm +++ b/tests/functional/mulf00.asm @@ -35,7 +35,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "mulf.asm" + #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -105,6 +107,7 @@ __MULF: ; Multiplication #line 26 "mulf00.bas" #line 1 "pushf.asm" + ; Routine to push Float pointed by HL ; Into the stack. Notice that the hl points to the last ; byte of the FP number. @@ -134,6 +137,7 @@ __FP_PUSH_REV: #line 27 "mulf00.bas" #line 1 "storef.asm" + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL diff --git a/tests/functional/mulf01.asm b/tests/functional/mulf01.asm index 120adde02..957fdd678 100644 --- a/tests/functional/mulf01.asm +++ b/tests/functional/mulf01.asm @@ -39,7 +39,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "mulf.asm" + #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -108,6 +110,7 @@ __MULF: ; Multiplication #line 30 "mulf01.bas" #line 1 "storef.asm" + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL diff --git a/tests/functional/mulf16a.asm b/tests/functional/mulf16a.asm index 7f9ca4c0e..6316c515b 100644 --- a/tests/functional/mulf16a.asm +++ b/tests/functional/mulf16a.asm @@ -36,7 +36,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "mulf16.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z @@ -70,6 +72,7 @@ __NEG32: ; Negates DEHL (Two's complement) #line 2 "mulf16.asm" #line 1 "_mul32.asm" + ; Ripped from: http://www.andreadrian.de/oldcpu/z80_number_cruncher.html#moztocid784223 ; Used with permission. ; Multiplies 32x32 bit integer (DEHL x D'E'H'L') diff --git a/tests/functional/ongoto.asm b/tests/functional/ongoto.asm index 8e2fef2de..6b4de7a23 100644 --- a/tests/functional/ongoto.asm +++ b/tests/functional/ongoto.asm @@ -140,6 +140,7 @@ __LABEL5: DEFW __LABEL__50 DEFW __LABEL__60 #line 1 "ongoto.asm" + ; ------------------------------------------------------ ; Implements ON .. GOTO ; ------------------------------------------------------ @@ -173,11 +174,13 @@ __ON_GOTO_START: jp (hl) #line 127 "ongoto.bas" #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -211,6 +214,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -261,7 +265,9 @@ __CLS_SCR: #line 7 "print.asm" #line 1 "in_screen.asm" + #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -332,6 +338,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -350,10 +357,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -406,6 +415,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -454,6 +464,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -481,6 +492,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -510,12 +522,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/home/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -574,7 +588,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/home/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -632,6 +646,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -665,6 +680,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -697,6 +713,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -732,6 +749,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1282,7 +1300,9 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes + #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1351,6 +1371,7 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/opt2_pstr.asm b/tests/functional/opt2_pstr.asm index 93dc8eb66..78cd19a7e 100644 --- a/tests/functional/opt2_pstr.asm +++ b/tests/functional/opt2_pstr.asm @@ -60,6 +60,7 @@ __LABEL0: DEFB 61h DEFB 32h #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -128,6 +129,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -377,7 +379,9 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 48 "opt2_pstr.bas" #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -446,6 +450,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -524,9 +529,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl diff --git a/tests/functional/opt3_einar.asm b/tests/functional/opt3_einar.asm index 761eff5a6..f79b43cbc 100644 --- a/tests/functional/opt3_einar.asm +++ b/tests/functional/opt3_einar.asm @@ -66,11 +66,13 @@ __LABEL3: DEFB 4Fh DEFB 4Bh #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -104,6 +106,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -154,7 +157,9 @@ __CLS_SCR: #line 7 "print.asm" #line 1 "in_screen.asm" + #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -225,6 +230,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -243,10 +249,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -299,6 +307,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -347,6 +356,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -374,6 +384,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -403,12 +414,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -467,7 +480,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -525,6 +538,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -558,6 +572,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -590,6 +605,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -625,6 +641,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1175,7 +1192,9 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes + #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1244,6 +1263,7 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/opt3_lcd5.asm b/tests/functional/opt3_lcd5.asm index 6c17d76c7..e1a0de674 100644 --- a/tests/functional/opt3_lcd5.asm +++ b/tests/functional/opt3_lcd5.asm @@ -372,6 +372,7 @@ _ScanNear__leave: exx ret #line 1 "and8.asm" + ; FASTCALL boolean and 8 version. ; result in Accumulator (0 False, not 0 True) ; __FASTCALL__ version (operands: A, H) @@ -385,7 +386,9 @@ __AND8: #line 363 "opt3_lcd5.bas" #line 1 "ftou32reg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z @@ -494,6 +497,7 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A #line 364 "opt3_lcd5.bas" #line 1 "lei16.asm" + __LEI16: PROC LOCAL checkParity @@ -512,7 +516,9 @@ checkParity: ENDP #line 365 "opt3_lcd5.bas" #line 1 "lti16.asm" + #line 1 "lei8.asm" + __LEI8: ; Signed <= comparison for 8bit int ; A <= H (registers) PROC diff --git a/tests/functional/opt3_sp.asm b/tests/functional/opt3_sp.asm index 9234e11b2..841a20d46 100644 --- a/tests/functional/opt3_sp.asm +++ b/tests/functional/opt3_sp.asm @@ -78,7 +78,9 @@ _test__leave: exx ret #line 1 "addf.asm" + #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -147,12 +149,14 @@ __ADDF: ; Addition #line 69 "opt3_sp.bas" #line 1 "ploadf.asm" + ; Parameter / Local var load ; A => Offset ; IX = Stack Frame ; RESULT: HL => IX + DE #line 1 "iloadf.asm" + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL @@ -191,12 +195,14 @@ __PLOADF: #line 70 "opt3_sp.bas" #line 1 "pstoref.asm" + ; Stores FP number in A ED CB at location HL+IX ; HL = Offset ; IX = Stack Frame ; A ED CB = FP Number #line 1 "storef.asm" + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -239,7 +245,9 @@ __PSTOREF: #line 71 "opt3_sp.bas" #line 1 "u32tofreg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z diff --git a/tests/functional/optconst.asm b/tests/functional/optconst.asm index 4f1540623..f91911d35 100644 --- a/tests/functional/optconst.asm +++ b/tests/functional/optconst.asm @@ -56,11 +56,13 @@ __LABEL__label2: ld c, l jp __END_PROGRAM #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -94,6 +96,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -144,7 +147,9 @@ __CLS_SCR: #line 7 "print.asm" #line 1 "in_screen.asm" + #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -215,6 +220,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -233,10 +239,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -289,6 +297,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -337,6 +346,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -364,6 +374,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -393,12 +404,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -457,7 +470,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -515,6 +528,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -548,6 +562,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -580,6 +595,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -615,6 +631,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1162,11 +1179,14 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes #line 46 "optconst.bas" #line 1 "printu32.asm" + #line 1 "printi32.asm" + #line 1 "printnum.asm" + __PRINTU_START: PROC @@ -1200,6 +1220,7 @@ __PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers #line 2 "printi32.asm" #line 1 "neg32.asm" + __ABS32: bit 7, d ret z @@ -1234,6 +1255,7 @@ __NEG32: ; Negates DEHL (Two's complement) #line 1 "div32.asm" + ; --------------------------------------------------------- __DIVU32: ; 32 bit unsigned division ; DEHL = Dividend, Stack Top = Divisor diff --git a/tests/functional/or32.asm b/tests/functional/or32.asm index 236888527..23935253e 100644 --- a/tests/functional/or32.asm +++ b/tests/functional/or32.asm @@ -67,6 +67,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "or32.asm" + __OR32: ; Performs logical operation A AND B ; between DEHL and TOP of the stack. ; Returns A = 0 (False) or A = FF (True) diff --git a/tests/functional/out0.asm b/tests/functional/out0.asm index 20b13b117..2a05f6fd5 100644 --- a/tests/functional/out0.asm +++ b/tests/functional/out0.asm @@ -37,7 +37,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "ftou32reg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z diff --git a/tests/functional/param0.asm b/tests/functional/param0.asm index b71915f90..748cef369 100644 --- a/tests/functional/param0.asm +++ b/tests/functional/param0.asm @@ -69,6 +69,7 @@ __LABEL1: DEFW 0001h DEFB 41h #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -137,6 +138,7 @@ __LABEL1: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -386,7 +388,9 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 56 "param0.bas" #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -455,6 +459,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -533,9 +538,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/home/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/home/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -655,11 +660,13 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 57 "param0.bas" #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -693,6 +700,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -745,6 +753,7 @@ __CLS_SCR: + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) @@ -774,6 +783,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -792,10 +802,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -848,6 +860,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -896,6 +909,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -923,6 +937,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -952,12 +967,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/home/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -1016,7 +1033,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/home/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -1074,6 +1091,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -1107,6 +1125,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -1139,6 +1158,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -1174,6 +1194,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1726,6 +1747,7 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes + ; PRINT command routine ; Prints string pointed by HL @@ -1780,7 +1802,9 @@ __PRINT_STR: #line 59 "param0.bas" #line 1 "strcat.asm" + #line 1 "strlen.asm" + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL diff --git a/tests/functional/param1.asm b/tests/functional/param1.asm index 4b56ce66b..769bb9233 100644 --- a/tests/functional/param1.asm +++ b/tests/functional/param1.asm @@ -61,15 +61,18 @@ __LABEL0: DEFW 0001h DEFB 61h #line 1 "print_eol_attr.asm" + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -103,6 +106,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -153,7 +157,9 @@ __CLS_SCR: #line 7 "print.asm" #line 1 "in_screen.asm" + #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -224,6 +230,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -242,10 +249,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -298,6 +307,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -346,6 +356,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -373,6 +384,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -402,12 +414,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -466,7 +480,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -524,6 +538,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -557,6 +572,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -589,6 +605,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -624,6 +641,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1180,7 +1198,9 @@ PRINT_EOL_ATTR: + #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1249,6 +1269,7 @@ PRINT_EOL_ATTR: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1551,6 +1572,7 @@ __PRINT_STR: #line 49 "param1.bas" #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -1564,7 +1586,9 @@ __PRINT_STR: #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1635,6 +1659,7 @@ __PRINT_STR: #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1741,9 +1766,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl diff --git a/tests/functional/param2.asm b/tests/functional/param2.asm index 4b71edcb4..dc5073be2 100644 --- a/tests/functional/param2.asm +++ b/tests/functional/param2.asm @@ -69,6 +69,7 @@ __LABEL1: DEFW 0001h DEFB 41h #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -137,6 +138,7 @@ __LABEL1: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -386,7 +388,9 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 56 "param2.bas" #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -455,6 +459,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -533,9 +538,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/home/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/home/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -655,11 +660,13 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 57 "param2.bas" #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -693,6 +700,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -745,6 +753,7 @@ __CLS_SCR: + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) @@ -774,6 +783,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -792,10 +802,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -848,6 +860,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -896,6 +909,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -923,6 +937,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -952,12 +967,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/home/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -1016,7 +1033,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/home/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -1074,6 +1091,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -1107,6 +1125,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -1139,6 +1158,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -1174,6 +1194,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1726,6 +1747,7 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes + ; PRINT command routine ; Prints string pointed by HL @@ -1780,7 +1802,9 @@ __PRINT_STR: #line 59 "param2.bas" #line 1 "strcat.asm" + #line 1 "strlen.asm" + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL diff --git a/tests/functional/parambyref1.asm b/tests/functional/parambyref1.asm index 62c1b1649..5f74839fb 100644 --- a/tests/functional/parambyref1.asm +++ b/tests/functional/parambyref1.asm @@ -69,11 +69,13 @@ _test__leave: exx ret #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -107,6 +109,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -157,7 +160,9 @@ __CLS_SCR: #line 7 "print.asm" #line 1 "in_screen.asm" + #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -228,6 +233,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -246,10 +252,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -302,6 +310,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -350,6 +359,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -377,6 +387,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -406,12 +417,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -470,7 +483,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -528,6 +541,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -561,6 +575,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -593,6 +608,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -628,6 +644,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1175,11 +1192,14 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes #line 59 "parambyref1.bas" #line 1 "printu16.asm" + #line 1 "printi16.asm" + #line 1 "printnum.asm" + __PRINTU_START: PROC @@ -1213,10 +1233,12 @@ __PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers #line 2 "printi16.asm" #line 1 "div16.asm" + ; 16 bit division and modulo functions ; for both signed and unsigned values #line 1 "neg16.asm" + ; Negates HL value (16 bit) __ABS16: bit 7, h diff --git a/tests/functional/paramstr3.asm b/tests/functional/paramstr3.asm index 33c21952d..19b3f0886 100644 --- a/tests/functional/paramstr3.asm +++ b/tests/functional/paramstr3.asm @@ -53,6 +53,7 @@ _p__leave: exx ret #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -121,6 +122,7 @@ _p__leave: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -370,7 +372,9 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 41 "paramstr3.bas" #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -439,6 +443,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -517,9 +522,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl diff --git a/tests/functional/paramstr4.asm b/tests/functional/paramstr4.asm index 44d681913..c30ff69fb 100644 --- a/tests/functional/paramstr4.asm +++ b/tests/functional/paramstr4.asm @@ -77,6 +77,7 @@ _r__leave: exx ret #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -145,6 +146,7 @@ _r__leave: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -394,7 +396,9 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 65 "paramstr4.bas" #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -463,6 +467,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -541,9 +546,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl diff --git a/tests/functional/paramstr5.asm b/tests/functional/paramstr5.asm index 937d6dae9..d52f1bd2b 100644 --- a/tests/functional/paramstr5.asm +++ b/tests/functional/paramstr5.asm @@ -77,6 +77,7 @@ _p_r__leave: exx ret #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -145,6 +146,7 @@ _p_r__leave: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -394,7 +396,9 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 65 "paramstr5.bas" #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -463,6 +467,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -541,9 +546,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl diff --git a/tests/functional/plot.asm b/tests/functional/plot.asm index 4766d884f..61e6b2738 100644 --- a/tests/functional/plot.asm +++ b/tests/functional/plot.asm @@ -59,7 +59,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "ftou32reg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z @@ -168,6 +170,7 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A #line 50 "plot.bas" #line 1 "plot.asm" + ; MIXED __FASTCAL__ / __CALLE__ PLOT Function ; Plots a point into the screen calling the ZX ROM PLOT routine @@ -175,6 +178,7 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A ; X in top of the stack #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -216,7 +220,9 @@ __STOP: ret #line 8 "plot.asm" #line 1 "in_screen.asm" + #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -279,6 +285,7 @@ __OUT_OF_SCREEN_ERR: ENDP #line 9 "plot.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen diff --git a/tests/functional/pooky0.asm b/tests/functional/pooky0.asm index ea0eaf190..68874614d 100644 --- a/tests/functional/pooky0.asm +++ b/tests/functional/pooky0.asm @@ -151,7 +151,9 @@ __EXIT_FUNCTION: exx ret #line 1 "addf.asm" + #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -222,6 +224,7 @@ __ADDF: ; Addition #line 1 "mulf.asm" + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) ; All of them uses A EDCB registers as 1st paramter. @@ -243,12 +246,14 @@ __MULF: ; Multiplication #line 143 "pooky0.bas" #line 1 "ploadf.asm" + ; Parameter / Local var load ; A => Offset ; IX = Stack Frame ; RESULT: HL => IX + DE #line 1 "iloadf.asm" + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL @@ -289,6 +294,7 @@ __PLOADF: #line 1 "subf.asm" + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) @@ -313,7 +319,9 @@ __SUBF: ; Subtraction #line 145 "pooky0.bas" #line 1 "u32tofreg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z diff --git a/tests/functional/print.asm b/tests/functional/print.asm index 89465b83e..88e6fd1c5 100644 --- a/tests/functional/print.asm +++ b/tests/functional/print.asm @@ -65,11 +65,13 @@ __LABEL0: DEFW 0001h DEFB 33h #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -103,6 +105,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -153,7 +156,9 @@ __CLS_SCR: #line 7 "print.asm" #line 1 "in_screen.asm" + #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -224,6 +229,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -242,10 +248,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -298,6 +306,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -346,6 +355,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -373,6 +383,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -402,12 +413,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -466,7 +479,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -524,6 +537,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -557,6 +571,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -589,6 +604,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -624,6 +640,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1171,6 +1188,7 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes #line 52 "print.bas" #line 1 "print_eol_attr.asm" + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes @@ -1182,11 +1200,14 @@ PRINT_EOL_ATTR: jp COPY_ATTR #line 53 "print.bas" #line 1 "printf.asm" + #line 1 "printstr.asm" + #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1255,6 +1276,7 @@ PRINT_EOL_ATTR: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1557,6 +1579,7 @@ __PRINT_STR: #line 2 "printf.asm" #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -1646,10 +1669,12 @@ __PRINTF: ; Prints a Fixed point Number stored in C ED LH #line 54 "print.bas" #line 1 "printf16.asm" + #line 1 "printnum.asm" + __PRINTU_START: PROC @@ -1684,11 +1709,14 @@ __PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers #line 2 "printf16.asm" #line 1 "printi16.asm" + #line 1 "div16.asm" + ; 16 bit division and modulo functions ; for both signed and unsigned values #line 1 "neg16.asm" + ; Negates HL value (16 bit) __ABS16: bit 7, h @@ -1842,6 +1870,7 @@ __PRINTU_LOOP: #line 3 "printf16.asm" #line 1 "neg32.asm" + __ABS32: bit 7, d ret z @@ -1931,7 +1960,9 @@ __PRINT_FIX_LOOP: #line 1 "printi8.asm" + #line 1 "div8.asm" + ; -------------------------------- __DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A @@ -2061,13 +2092,17 @@ __PRINTU_LOOP: #line 1 "printu16.asm" + #line 59 "print.bas" #line 1 "printu8.asm" + #line 60 "print.bas" #line 1 "strcat.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -2174,9 +2209,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -2253,6 +2288,7 @@ __MEM_SUBTRACT: #line 2 "strcat.asm" #line 1 "strlen.asm" + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL diff --git a/tests/functional/print42.asm b/tests/functional/print42.asm index 1d8724881..de632bbe7 100644 --- a/tests/functional/print42.asm +++ b/tests/functional/print42.asm @@ -472,6 +472,7 @@ _print42__leave: exx ret #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -540,6 +541,7 @@ _print42__leave: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/print64.asm b/tests/functional/print64.asm index 833f22ebe..09523c5c9 100644 --- a/tests/functional/print64.asm +++ b/tests/functional/print64.asm @@ -301,6 +301,7 @@ _print64__leave: exx ret #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -369,6 +370,7 @@ _print64__leave: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/randomize.asm b/tests/functional/randomize.asm index dd64c634f..c100b50b6 100644 --- a/tests/functional/randomize.asm +++ b/tests/functional/randomize.asm @@ -33,6 +33,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "random.asm" + ; RANDOM functions RANDOMIZE: diff --git a/tests/functional/save01.asm b/tests/functional/save01.asm index d4dab681d..b3f59de4b 100644 --- a/tests/functional/save01.asm +++ b/tests/functional/save01.asm @@ -48,7 +48,9 @@ __LABEL0: DEFB 74h DEFB 73h #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -117,6 +119,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -158,6 +161,7 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -321,9 +325,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -443,6 +447,7 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 36 "save01.bas" #line 1 "save.asm" + ; Save code "XXX" at address YYY of length ZZZ ; Parameters in the stack are XXX (16 bit) address of string name ; (only first 12 chars will be taken into account) diff --git a/tests/functional/save02.asm b/tests/functional/save02.asm index c36291968..6a8dfb644 100644 --- a/tests/functional/save02.asm +++ b/tests/functional/save02.asm @@ -45,7 +45,9 @@ __LABEL0: DEFB 74h DEFB 31h #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -114,6 +116,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -155,6 +158,7 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -318,9 +322,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -440,6 +444,7 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 33 "save02.bas" #line 1 "save.asm" + ; Save code "XXX" at address YYY of length ZZZ ; Parameters in the stack are XXX (16 bit) address of string name ; (only first 12 chars will be taken into account) diff --git a/tests/functional/save03.asm b/tests/functional/save03.asm index c2f49c239..40baabe36 100644 --- a/tests/functional/save03.asm +++ b/tests/functional/save03.asm @@ -44,7 +44,9 @@ __LABEL0: DEFB 73h DEFB 74h #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -113,6 +115,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -154,6 +157,7 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -317,9 +321,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -439,6 +443,7 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 32 "save03.bas" #line 1 "save.asm" + ; Save code "XXX" at address YYY of length ZZZ ; Parameters in the stack are XXX (16 bit) address of string name ; (only first 12 chars will be taken into account) diff --git a/tests/functional/sgnf.asm b/tests/functional/sgnf.asm index 070e8f2f5..fc455ba9f 100644 --- a/tests/functional/sgnf.asm +++ b/tests/functional/sgnf.asm @@ -32,7 +32,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sgnf.asm" + #line 1 "sgn.asm" + ; Returns SGN (SIGN) for 32, 16 and 8 bits signed integers, Fixed and FLOAT PROC diff --git a/tests/functional/sgnf16.asm b/tests/functional/sgnf16.asm index c50045f21..29691824e 100644 --- a/tests/functional/sgnf16.asm +++ b/tests/functional/sgnf16.asm @@ -31,7 +31,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sgnf16.asm" + #line 1 "sgn.asm" + ; Returns SGN (SIGN) for 32, 16 and 8 bits signed integers, Fixed and FLOAT PROC diff --git a/tests/functional/sgni16.asm b/tests/functional/sgni16.asm index d5702bd4d..7d8b74fd0 100644 --- a/tests/functional/sgni16.asm +++ b/tests/functional/sgni16.asm @@ -30,7 +30,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sgni16.asm" + #line 1 "sgn.asm" + ; Returns SGN (SIGN) for 32, 16 and 8 bits signed integers, Fixed and FLOAT PROC diff --git a/tests/functional/sgni32.asm b/tests/functional/sgni32.asm index 9db7778e8..866fc41f6 100644 --- a/tests/functional/sgni32.asm +++ b/tests/functional/sgni32.asm @@ -31,7 +31,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sgni32.asm" + #line 1 "sgn.asm" + ; Returns SGN (SIGN) for 32, 16 and 8 bits signed integers, Fixed and FLOAT PROC diff --git a/tests/functional/sgni8.asm b/tests/functional/sgni8.asm index 1c0272690..7c9adcfcd 100644 --- a/tests/functional/sgni8.asm +++ b/tests/functional/sgni8.asm @@ -30,6 +30,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sgni8.asm" + ; Returns SGN (SIGN) for 8 bits signed integer __SGNI8: diff --git a/tests/functional/sgnu16.asm b/tests/functional/sgnu16.asm index 8189cd945..fdefd7421 100644 --- a/tests/functional/sgnu16.asm +++ b/tests/functional/sgnu16.asm @@ -30,6 +30,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sgnu16.asm" + ; Returns SGN (SIGN) for 16 bits unsigned integer __SGNU16: diff --git a/tests/functional/sgnu32.asm b/tests/functional/sgnu32.asm index 1e9314731..b14f9ae3d 100644 --- a/tests/functional/sgnu32.asm +++ b/tests/functional/sgnu32.asm @@ -31,6 +31,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sgnu32.asm" + ; Returns SGN (SIGN) for 32 bits unsigned integer __SGNU32: diff --git a/tests/functional/sgnu8.asm b/tests/functional/sgnu8.asm index a0c5c4f9a..93b606177 100644 --- a/tests/functional/sgnu8.asm +++ b/tests/functional/sgnu8.asm @@ -30,6 +30,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sgnu8.asm" + ; Returns SGN (SIGN) for 8 bits unsigned integera __SGNU8: diff --git a/tests/functional/sigilfunc.asm b/tests/functional/sigilfunc.asm index e0cb3f5fa..ecbd0367f 100644 --- a/tests/functional/sigilfunc.asm +++ b/tests/functional/sigilfunc.asm @@ -46,7 +46,9 @@ _test__leave: __LABEL0: DEFW 0000h #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -115,6 +117,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -156,6 +159,7 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -319,9 +323,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -441,6 +445,7 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 34 "sigilfunc.bas" #line 1 "storestr2.asm" + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication @@ -449,6 +454,7 @@ __LOADSTR: ; __FASTCALL__ entry ; freeing (HL) previously. #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/simple.asm b/tests/functional/simple.asm index e49b98724..a4eb6143d 100644 --- a/tests/functional/simple.asm +++ b/tests/functional/simple.asm @@ -48,11 +48,13 @@ __LABEL0: DEFB 4Ch DEFB 44h #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -86,6 +88,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -136,7 +139,9 @@ __CLS_SCR: #line 7 "print.asm" #line 1 "in_screen.asm" + #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -207,6 +212,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -225,10 +231,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -281,6 +289,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -329,6 +338,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -356,6 +366,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -385,12 +396,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -449,7 +462,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -507,6 +520,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -540,6 +554,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -572,6 +587,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -607,6 +623,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1157,7 +1174,9 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes + #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1226,6 +1245,7 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/slice0.asm b/tests/functional/slice0.asm index 2c0f20f71..005b88490 100644 --- a/tests/functional/slice0.asm +++ b/tests/functional/slice0.asm @@ -41,6 +41,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "storestr2.asm" + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication @@ -49,6 +50,7 @@ __CALL_BACK__: ; freeing (HL) previously. #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -117,6 +119,7 @@ __CALL_BACK__: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -398,6 +401,7 @@ __STORE_STR2: #line 29 "slice0.bas" #line 1 "strslice.asm" + ; String slicing library ; HL = Str pointer ; DE = String start @@ -415,6 +419,7 @@ __STORE_STR2: ; #line 1 "strlen.asm" + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL @@ -433,6 +438,7 @@ __STRLEN: ; Direct FASTCALL entry #line 18 "strslice.asm" #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -501,6 +507,7 @@ __STRLEN: ; Direct FASTCALL entry ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -579,9 +586,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl diff --git a/tests/functional/slice2.asm b/tests/functional/slice2.asm index 06d5d5ff6..8d3da9761 100644 --- a/tests/functional/slice2.asm +++ b/tests/functional/slice2.asm @@ -125,6 +125,7 @@ __LABEL0: DEFB 6Ch DEFB 64h #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -133,6 +134,7 @@ __LABEL0: ; Our faster implementation #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -206,6 +208,7 @@ __CLS_SCR: #line 113 "slice2.bas" #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -247,6 +250,7 @@ __STOP: ret #line 114 "slice2.bas" #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -315,6 +319,7 @@ __STOP: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -564,7 +569,9 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 115 "slice2.bas" #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -671,9 +678,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -793,6 +800,7 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 116 "slice2.bas" #line 1 "pstorestr2.asm" + ; vim:ts=4:et:sw=4 ; ; Stores an string (pointer to the HEAP by DE) into the address pointed @@ -801,6 +809,7 @@ __LOADSTR: ; __FASTCALL__ entry ; #line 1 "storestr2.asm" + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication @@ -850,6 +859,7 @@ __PSTORE_STR2: #line 117 "slice2.bas" #line 1 "strlen.asm" + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL @@ -868,6 +878,7 @@ __STRLEN: ; Direct FASTCALL entry #line 118 "slice2.bas" #line 1 "strslice.asm" + ; String slicing library ; HL = Str pointer ; DE = String start diff --git a/tests/functional/spfill.asm b/tests/functional/spfill.asm index 454b9fa72..0a8e6dddb 100644 --- a/tests/functional/spfill.asm +++ b/tests/functional/spfill.asm @@ -65,7 +65,7 @@ _SPFill: call SPPFill_start pop ix ret -#line 1 "PixelUp.asm" +#line 1 "/src/zxb/trunk/library-asm/SP/PixelUp.asm" SP.PixelUp: ld a,h dec h @@ -86,8 +86,8 @@ _SPFill: ld h,a cp $40 ret -#line 31 "Fill.bas" -#line 1 "PixelDown.asm" +#line 31 "/src/zxb/trunk/library/SP/Fill.bas" +#line 1 "/src/zxb/trunk/library-asm/SP/PixelDown.asm" SP.PixelDown: inc h ld a,h @@ -109,8 +109,8 @@ _SPFill: cp $58 ccf ret -#line 32 "Fill.bas" -#line 1 "CharLeft.asm" +#line 32 "/src/zxb/trunk/library/SP/Fill.bas" +#line 1 "/src/zxb/trunk/library-asm/SP/CharLeft.asm" SP.CharLeft: ld a,l dec l @@ -121,8 +121,8 @@ _SPFill: ld h,a cp $40 ret -#line 33 "Fill.bas" -#line 1 "CharRight.asm" +#line 33 "/src/zxb/trunk/library/SP/Fill.bas" +#line 1 "/src/zxb/trunk/library-asm/SP/CharRight.asm" SP.CharRight: inc l ret nz @@ -132,8 +132,8 @@ _SPFill: cp $58 ccf ret -#line 34 "Fill.bas" -#line 1 "GetScrnAddr.asm" +#line 34 "/src/zxb/trunk/library/SP/Fill.bas" +#line 1 "/src/zxb/trunk/library-asm/SP/GetScrnAddr.asm" SPGetScrnAddr: and $07 or $40 @@ -165,7 +165,7 @@ norotate: or l ld e,a ret -#line 35 "Fill.bas" +#line 35 "/src/zxb/trunk/library/SP/Fill.bas" SPPFill_IXBuffer: DEFB 0,0 SPPFill_start: @@ -481,10 +481,12 @@ __LABEL0: DEFW 0001h DEFB 61h #line 1 "circle.asm" + ; Bresenham's like circle algorithm ; best known as Middle Point Circle drawing algorithm #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -526,6 +528,7 @@ __STOP: ret #line 5 "circle.asm" #line 1 "plot.asm" + ; MIXED __FASTCAL__ / __CALLE__ PLOT Function ; Plots a point into the screen calling the ZX ROM PLOT routine @@ -534,7 +537,9 @@ __STOP: #line 1 "in_screen.asm" + #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -597,6 +602,7 @@ __OUT_OF_SCREEN_ERR: ENDP #line 9 "plot.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -937,6 +943,7 @@ __CIRCLE_PLOT: #line 469 "spfill.bas" #line 1 "pause.asm" + ; The PAUSE statement (Calling the ROM) __PAUSE: @@ -945,6 +952,7 @@ __PAUSE: jp 1F3Dh ; PAUSE_1 #line 471 "spfill.bas" #line 1 "usr_str.asm" + ; This function just returns the address of the UDG of the given str. ; If the str is EMPTY or not a letter, 0 is returned and ERR_NR set ; to "A: Invalid Argument" @@ -954,6 +962,7 @@ __PAUSE: #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -966,6 +975,7 @@ __PAUSE: #line 10 "usr_str.asm" #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1034,6 +1044,7 @@ __PAUSE: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/stoperr.asm b/tests/functional/stoperr.asm index e07508873..0ded9c6ad 100644 --- a/tests/functional/stoperr.asm +++ b/tests/functional/stoperr.asm @@ -35,6 +35,7 @@ __CALL_BACK__: ld c, l jp __END_PROGRAM #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: diff --git a/tests/functional/storecstr.asm b/tests/functional/storecstr.asm index 444e9c921..fb2d2fcd5 100644 --- a/tests/functional/storecstr.asm +++ b/tests/functional/storecstr.asm @@ -40,6 +40,7 @@ __LABEL0: DEFB 6Ch DEFB 6Fh #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -53,7 +54,9 @@ __LABEL0: #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -123,6 +126,7 @@ __LABEL0: #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -164,6 +168,7 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -233,6 +238,7 @@ __STOP: #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -396,9 +402,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -475,6 +481,7 @@ __MEM_SUBTRACT: #line 71 "realloc.asm" #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/storef.asm b/tests/functional/storef.asm index 73461fd5c..cc15fd86c 100644 --- a/tests/functional/storef.asm +++ b/tests/functional/storef.asm @@ -32,6 +32,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "storef.asm" + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL diff --git a/tests/functional/storestr0.asm b/tests/functional/storestr0.asm index c5187874c..f7e4eafd0 100644 --- a/tests/functional/storestr0.asm +++ b/tests/functional/storestr0.asm @@ -33,6 +33,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -46,7 +47,9 @@ __CALL_BACK__: #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -116,6 +119,7 @@ __CALL_BACK__: #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -157,6 +161,7 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -226,6 +231,7 @@ __STOP: #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -389,9 +395,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -468,6 +474,7 @@ __MEM_SUBTRACT: #line 71 "realloc.asm" #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/storestr1.asm b/tests/functional/storestr1.asm index 3c2e64b16..4f4a0225e 100644 --- a/tests/functional/storestr1.asm +++ b/tests/functional/storestr1.asm @@ -70,6 +70,7 @@ __LABEL0: DEFB 6Ch DEFB 6Fh #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -138,6 +139,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -387,6 +389,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 58 "storestr1.bas" #line 1 "pstorestr.asm" + ; vim:ts=4:et:sw=4 ; ; Stores an string (pointer to the HEAP by DE) into the address pointed @@ -394,6 +397,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -407,7 +411,9 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -477,6 +483,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -518,6 +525,7 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -624,9 +632,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl diff --git a/tests/functional/storestr2.asm b/tests/functional/storestr2.asm index d26eed880..3b363c622 100644 --- a/tests/functional/storestr2.asm +++ b/tests/functional/storestr2.asm @@ -76,6 +76,7 @@ __LABEL0: DEFB 6Ch DEFB 6Fh #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -144,6 +145,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -393,7 +395,9 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 64 "storestr2.bas" #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -462,6 +466,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -540,9 +545,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -662,6 +667,7 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 65 "storestr2.bas" #line 1 "pstorestr.asm" + ; vim:ts=4:et:sw=4 ; ; Stores an string (pointer to the HEAP by DE) into the address pointed @@ -669,6 +675,7 @@ __LOADSTR: ; __FASTCALL__ entry ; #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -682,7 +689,9 @@ __LOADSTR: ; __FASTCALL__ entry #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/str0.asm b/tests/functional/str0.asm index ac916f697..55138ad61 100644 --- a/tests/functional/str0.asm +++ b/tests/functional/str0.asm @@ -72,6 +72,7 @@ __LABEL0: DEFW 0001h DEFB 31h #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -140,6 +141,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -389,15 +391,18 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 59 "str0.bas" #line 1 "print_eol_attr.asm" + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -431,6 +436,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -481,7 +487,9 @@ __CLS_SCR: #line 7 "print.asm" #line 1 "in_screen.asm" + #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -552,6 +560,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -570,10 +579,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -626,6 +637,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -674,6 +686,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -701,6 +714,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -730,12 +744,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -794,7 +810,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -852,6 +868,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -885,6 +902,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -917,6 +935,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -952,6 +971,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1510,6 +1530,7 @@ PRINT_EOL_ATTR: + ; PRINT command routine ; Prints string pointed by HL @@ -1563,6 +1584,7 @@ __PRINT_STR: #line 61 "str0.bas" #line 1 "str.asm" + ; The STR$( ) BASIC function implementation ; Given a FP number in C ED LH @@ -1570,6 +1592,7 @@ __PRINT_STR: ; containing the FP number string representation #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1676,9 +1699,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -1755,6 +1778,7 @@ __MEM_SUBTRACT: #line 8 "str.asm" #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -1873,7 +1897,9 @@ __STR_END: #line 62 "str0.bas" #line 1 "strcat.asm" + #line 1 "strlen.asm" + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL @@ -2017,7 +2043,9 @@ __STRCATEND: #line 63 "str0.bas" #line 1 "u32tofreg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z diff --git a/tests/functional/str00.asm b/tests/functional/str00.asm index 857b38a81..68f7b4c78 100644 --- a/tests/functional/str00.asm +++ b/tests/functional/str00.asm @@ -37,6 +37,7 @@ __LABEL0: DEFB 35h DEFB 32h #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -50,7 +51,9 @@ __LABEL0: #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -120,6 +123,7 @@ __LABEL0: #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -161,6 +165,7 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -230,6 +235,7 @@ __STOP: #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -393,9 +399,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -472,6 +478,7 @@ __MEM_SUBTRACT: #line 71 "realloc.asm" #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/str01.asm b/tests/functional/str01.asm index 84a4aaf71..5a48022a4 100644 --- a/tests/functional/str01.asm +++ b/tests/functional/str01.asm @@ -37,6 +37,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "storestr2.asm" + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication @@ -45,6 +46,7 @@ __CALL_BACK__: ; freeing (HL) previously. #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -113,6 +115,7 @@ __CALL_BACK__: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -394,6 +397,7 @@ __STORE_STR2: #line 25 "str01.bas" #line 1 "str.asm" + ; The STR$( ) BASIC function implementation ; Given a FP number in C ED LH @@ -401,6 +405,7 @@ __STORE_STR2: ; containing the FP number string representation #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -469,6 +474,7 @@ __STORE_STR2: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -547,9 +553,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -626,6 +632,7 @@ __MEM_SUBTRACT: #line 8 "str.asm" #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -673,6 +680,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK jp __FPSTACK_PUSH #line 9 "str.asm" #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -754,7 +762,9 @@ __STR_END: #line 26 "str01.bas" #line 1 "u32tofreg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z diff --git a/tests/functional/str02.asm b/tests/functional/str02.asm index 80ad56307..668462c49 100644 --- a/tests/functional/str02.asm +++ b/tests/functional/str02.asm @@ -52,6 +52,7 @@ __LABEL0: DEFB 6Fh DEFB 20h #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -120,6 +121,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -161,6 +163,7 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -324,9 +327,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -403,6 +406,7 @@ __MEM_SUBTRACT: #line 40 "str02.bas" #line 1 "storestr2.asm" + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication @@ -411,6 +415,7 @@ __MEM_SUBTRACT: ; freeing (HL) previously. #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -634,6 +639,7 @@ __STORE_STR2: #line 41 "str02.bas" #line 1 "str.asm" + ; The STR$( ) BASIC function implementation ; Given a FP number in C ED LH @@ -642,6 +648,7 @@ __STORE_STR2: #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -689,6 +696,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK jp __FPSTACK_PUSH #line 9 "str.asm" #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -771,7 +779,9 @@ __STR_END: #line 42 "str02.bas" #line 1 "strcat.asm" + #line 1 "strlen.asm" + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL @@ -915,7 +925,9 @@ __STRCATEND: #line 43 "str02.bas" #line 1 "u32tofreg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z diff --git a/tests/functional/stradd.asm b/tests/functional/stradd.asm index 187f174c5..efa6f801b 100644 --- a/tests/functional/stradd.asm +++ b/tests/functional/stradd.asm @@ -54,6 +54,7 @@ __LABEL1: DEFB 4Ch DEFB 44h #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -67,7 +68,9 @@ __LABEL1: #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -137,6 +140,7 @@ __LABEL1: #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -178,6 +182,7 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -247,6 +252,7 @@ __STOP: #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -410,9 +416,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/home/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/home/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -489,6 +495,7 @@ __MEM_SUBTRACT: #line 71 "realloc.asm" #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -896,6 +903,7 @@ __STORE_STR: #line 42 "stradd.bas" #line 1 "storestr2.asm" + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication @@ -938,7 +946,9 @@ __STORE_STR2: #line 43 "stradd.bas" #line 1 "strcat.asm" + #line 1 "strlen.asm" + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL diff --git a/tests/functional/strbase.asm b/tests/functional/strbase.asm index 15ce5a912..4ba2a71d8 100644 --- a/tests/functional/strbase.asm +++ b/tests/functional/strbase.asm @@ -64,6 +64,7 @@ __LABEL1: DEFW 0001h DEFB 6Fh #line 1 "letsubstr.asm" + ; Substring assigment eg. LET a$(p0 TO p1) = "xxxx" ; HL = Start of string ; TOP of the stack -> p1 (16 bit, unsigned) @@ -74,6 +75,7 @@ __LABEL1: ; TOP -3 B$ address #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -142,6 +144,7 @@ __LABEL1: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -541,7 +544,9 @@ __FREE_STR: #line 52 "strbase.bas" #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -610,6 +615,7 @@ __FREE_STR: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -688,9 +694,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -810,6 +816,7 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 53 "strbase.bas" #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -823,7 +830,9 @@ __LOADSTR: ; __FASTCALL__ entry #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1112,6 +1121,7 @@ __STORE_STR: #line 54 "strbase.bas" #line 1 "storestr2.asm" + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication @@ -1153,6 +1163,7 @@ __STORE_STR2: #line 55 "strbase.bas" #line 1 "strslice.asm" + ; String slicing library ; HL = Str pointer ; DE = String start @@ -1170,6 +1181,7 @@ __STORE_STR2: ; #line 1 "strlen.asm" + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL diff --git a/tests/functional/strbase2.asm b/tests/functional/strbase2.asm index 5947f1de3..294ce144c 100644 --- a/tests/functional/strbase2.asm +++ b/tests/functional/strbase2.asm @@ -73,6 +73,7 @@ __LABEL1: DEFW 0001h DEFB 6Fh #line 1 "letsubstr.asm" + ; Substring assigment eg. LET a$(p0 TO p1) = "xxxx" ; HL = Start of string ; TOP of the stack -> p1 (16 bit, unsigned) @@ -83,6 +84,7 @@ __LABEL1: ; TOP -3 B$ address #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -151,6 +153,7 @@ __LABEL1: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -550,7 +553,9 @@ __FREE_STR: #line 60 "strbase2.bas" #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -619,6 +624,7 @@ __FREE_STR: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -697,9 +703,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -819,15 +825,18 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 61 "strbase2.bas" #line 1 "print_eol_attr.asm" + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -861,6 +870,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -913,6 +923,7 @@ __CLS_SCR: + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) @@ -942,6 +953,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -960,10 +972,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -1016,6 +1030,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -1064,6 +1079,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -1091,6 +1107,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -1120,12 +1137,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -1184,7 +1203,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -1242,6 +1261,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -1275,6 +1295,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -1307,6 +1328,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -1342,6 +1364,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1900,6 +1923,7 @@ PRINT_EOL_ATTR: + ; PRINT command routine ; Prints string pointed by HL @@ -1953,6 +1977,7 @@ __PRINT_STR: #line 63 "strbase2.bas" #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -1966,7 +1991,9 @@ __PRINT_STR: #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -2255,6 +2282,7 @@ __STORE_STR: #line 64 "strbase2.bas" #line 1 "storestr2.asm" + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication @@ -2296,6 +2324,7 @@ __STORE_STR2: #line 65 "strbase2.bas" #line 1 "strslice.asm" + ; String slicing library ; HL = Str pointer ; DE = String start @@ -2313,6 +2342,7 @@ __STORE_STR2: ; #line 1 "strlen.asm" + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL diff --git a/tests/functional/stringfunc.asm b/tests/functional/stringfunc.asm index f6aff1d26..924ec9052 100644 --- a/tests/functional/stringfunc.asm +++ b/tests/functional/stringfunc.asm @@ -50,6 +50,7 @@ __LABEL0: DEFB 6Ch DEFB 6Fh #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -118,6 +119,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -367,7 +369,9 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 38 "stringfunc.bas" #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -436,6 +440,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -514,9 +519,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl diff --git a/tests/functional/stringparam.asm b/tests/functional/stringparam.asm index 686a10899..7d0dcf9df 100644 --- a/tests/functional/stringparam.asm +++ b/tests/functional/stringparam.asm @@ -66,6 +66,7 @@ __LABEL0: DEFB 6Ch DEFB 6Fh #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -134,6 +135,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -383,7 +385,9 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 53 "stringparam.bas" #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -452,6 +456,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -530,9 +535,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -652,15 +657,18 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 54 "stringparam.bas" #line 1 "print_eol_attr.asm" + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -694,6 +702,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -746,6 +755,7 @@ __CLS_SCR: + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) @@ -775,6 +785,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -793,10 +804,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -849,6 +862,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -897,6 +911,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -924,6 +939,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -953,12 +969,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -1017,7 +1035,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -1075,6 +1093,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -1108,6 +1127,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -1140,6 +1160,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -1175,6 +1196,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1733,6 +1755,7 @@ PRINT_EOL_ATTR: + ; PRINT command routine ; Prints string pointed by HL diff --git a/tests/functional/strlocal0.asm b/tests/functional/strlocal0.asm index 6b3f746d4..ac50795cc 100644 --- a/tests/functional/strlocal0.asm +++ b/tests/functional/strlocal0.asm @@ -70,6 +70,7 @@ __LABEL0: DEFB 6Ch DEFB 64h #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -138,6 +139,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -387,15 +389,18 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 57 "strlocal0.bas" #line 1 "print_eol_attr.asm" + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -429,6 +434,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -479,7 +485,9 @@ __CLS_SCR: #line 7 "print.asm" #line 1 "in_screen.asm" + #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -550,6 +558,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -568,10 +577,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -624,6 +635,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -672,6 +684,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -699,6 +712,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -728,12 +742,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -792,7 +808,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -850,6 +866,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -883,6 +900,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -915,6 +933,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -950,6 +969,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1508,6 +1528,7 @@ PRINT_EOL_ATTR: + ; PRINT command routine ; Prints string pointed by HL @@ -1561,6 +1582,7 @@ __PRINT_STR: #line 59 "strlocal0.bas" #line 1 "pstorestr.asm" + ; vim:ts=4:et:sw=4 ; ; Stores an string (pointer to the HEAP by DE) into the address pointed @@ -1568,6 +1590,7 @@ __PRINT_STR: ; #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -1581,7 +1604,9 @@ __PRINT_STR: #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1652,6 +1677,7 @@ __PRINT_STR: #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1758,9 +1784,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl diff --git a/tests/functional/strparam0.asm b/tests/functional/strparam0.asm index e5f1b4010..0cd578fb8 100644 --- a/tests/functional/strparam0.asm +++ b/tests/functional/strparam0.asm @@ -96,6 +96,7 @@ __LABEL0: DEFB 6Ch DEFB 64h #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -164,6 +165,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -413,7 +415,9 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 83 "strparam0.bas" #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -482,6 +486,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -560,9 +565,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -682,15 +687,18 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 84 "strparam0.bas" #line 1 "print_eol_attr.asm" + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -724,6 +732,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -776,6 +785,7 @@ __CLS_SCR: + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) @@ -805,6 +815,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -823,10 +834,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -879,6 +892,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -927,6 +941,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -954,6 +969,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -983,12 +999,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -1047,7 +1065,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -1105,6 +1123,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -1138,6 +1157,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -1170,6 +1190,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -1205,6 +1226,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1763,6 +1785,7 @@ PRINT_EOL_ATTR: + ; PRINT command routine ; Prints string pointed by HL diff --git a/tests/functional/strparam1.asm b/tests/functional/strparam1.asm index db9053a02..e8fc1654d 100644 --- a/tests/functional/strparam1.asm +++ b/tests/functional/strparam1.asm @@ -80,6 +80,7 @@ __LABEL0: DEFB 6Fh DEFB 20h #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -148,6 +149,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -189,6 +191,7 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -352,9 +355,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -431,6 +434,7 @@ __MEM_SUBTRACT: #line 68 "strparam1.bas" #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -622,6 +626,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 69 "strparam1.bas" #line 1 "pstorestr.asm" + ; vim:ts=4:et:sw=4 ; ; Stores an string (pointer to the HEAP by DE) into the address pointed @@ -629,6 +634,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -642,7 +648,9 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -939,6 +947,7 @@ __PSTORE_STR: #line 70 "strparam1.bas" #line 1 "str.asm" + ; The STR$( ) BASIC function implementation ; Given a FP number in C ED LH @@ -947,6 +956,7 @@ __PSTORE_STR: #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -994,6 +1004,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK jp __FPSTACK_PUSH #line 9 "str.asm" #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -1076,7 +1087,9 @@ __STR_END: #line 71 "strparam1.bas" #line 1 "strcat.asm" + #line 1 "strlen.asm" + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL @@ -1220,7 +1233,9 @@ __STRCATEND: #line 72 "strparam1.bas" #line 1 "u32tofreg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z diff --git a/tests/functional/strparam2.asm b/tests/functional/strparam2.asm index 22d51f398..8ce2974a9 100644 --- a/tests/functional/strparam2.asm +++ b/tests/functional/strparam2.asm @@ -83,15 +83,18 @@ __LABEL0: DEFB 49h DEFB 43h #line 1 "print_eol_attr.asm" + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -125,6 +128,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -175,7 +179,9 @@ __CLS_SCR: #line 7 "print.asm" #line 1 "in_screen.asm" + #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -246,6 +252,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -264,10 +271,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -320,6 +329,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -368,6 +378,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -395,6 +406,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -424,12 +436,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -488,7 +502,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -546,6 +560,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -579,6 +594,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -611,6 +627,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -646,6 +663,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1202,7 +1220,9 @@ PRINT_EOL_ATTR: + #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1271,6 +1291,7 @@ PRINT_EOL_ATTR: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1573,6 +1594,7 @@ __PRINT_STR: #line 71 "strparam2.bas" #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -1586,7 +1608,9 @@ __PRINT_STR: #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1657,6 +1681,7 @@ __PRINT_STR: #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1763,9 +1788,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl diff --git a/tests/functional/strparam3.asm b/tests/functional/strparam3.asm index a7a241eb1..3129bd5ea 100644 --- a/tests/functional/strparam3.asm +++ b/tests/functional/strparam3.asm @@ -90,6 +90,7 @@ __LABEL0: DEFB 49h DEFB 43h #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -158,6 +159,7 @@ __LABEL0: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -407,7 +409,9 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 77 "strparam3.bas" #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -476,6 +480,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -554,9 +559,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -676,15 +681,18 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 78 "strparam3.bas" #line 1 "print_eol_attr.asm" + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -718,6 +726,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -770,6 +779,7 @@ __CLS_SCR: + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) @@ -799,6 +809,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -817,10 +828,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -873,6 +886,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -921,6 +935,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -948,6 +963,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -977,12 +993,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -1041,7 +1059,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -1099,6 +1117,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -1132,6 +1151,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -1164,6 +1184,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -1199,6 +1220,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1757,6 +1779,7 @@ PRINT_EOL_ATTR: + ; PRINT command routine ; Prints string pointed by HL diff --git a/tests/functional/strsigil.asm b/tests/functional/strsigil.asm index 253001735..12a87e851 100644 --- a/tests/functional/strsigil.asm +++ b/tests/functional/strsigil.asm @@ -47,8 +47,10 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "asc.asm" + ; Returns the ascii code for the given str #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -117,6 +119,7 @@ __CALL_BACK__: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -400,7 +403,9 @@ __ASC_END: ENDP #line 35 "strsigil.bas" #line 1 "ftou32reg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z @@ -509,6 +514,7 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A #line 36 "strsigil.bas" #line 1 "strslice.asm" + ; String slicing library ; HL = Str pointer ; DE = String start @@ -526,6 +532,7 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A ; #line 1 "strlen.asm" + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL @@ -544,6 +551,7 @@ __STRLEN: ; Direct FASTCALL entry #line 18 "strslice.asm" #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -612,6 +620,7 @@ __STRLEN: ; Direct FASTCALL entry ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -690,9 +699,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl diff --git a/tests/functional/subf00.asm b/tests/functional/subf00.asm index 003cced54..cabe1746e 100644 --- a/tests/functional/subf00.asm +++ b/tests/functional/subf00.asm @@ -36,6 +36,7 @@ __CALL_BACK__: DEFW 0 #line 1 "pushf.asm" + ; Routine to push Float pointed by HL ; Into the stack. Notice that the hl points to the last ; byte of the FP number. @@ -65,6 +66,7 @@ __FP_PUSH_REV: #line 26 "subf00.bas" #line 1 "storef.asm" + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -95,7 +97,9 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL #line 27 "subf00.bas" #line 1 "subf.asm" + #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- diff --git a/tests/functional/subf01.asm b/tests/functional/subf01.asm index 390a54090..9f8af4a72 100644 --- a/tests/functional/subf01.asm +++ b/tests/functional/subf01.asm @@ -39,6 +39,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "storef.asm" + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -69,7 +70,9 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL #line 30 "subf01.bas" #line 1 "subf.asm" + #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- diff --git a/tests/functional/subf16c.asm b/tests/functional/subf16c.asm index 44a74e750..109ae9097 100644 --- a/tests/functional/subf16c.asm +++ b/tests/functional/subf16c.asm @@ -59,6 +59,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sub32.asm" + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) @@ -88,6 +89,7 @@ __SUB32: ret #line 50 "subf16c.bas" #line 1 "swap32.asm" + ; Exchanges current DE HL with the ; ones in the stack diff --git a/tests/functional/subi32c.asm b/tests/functional/subi32c.asm index ba4bc4c57..526185984 100644 --- a/tests/functional/subi32c.asm +++ b/tests/functional/subi32c.asm @@ -68,6 +68,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sub32.asm" + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) @@ -97,6 +98,7 @@ __SUB32: ret #line 59 "subi32c.bas" #line 1 "swap32.asm" + ; Exchanges current DE HL with the ; ones in the stack diff --git a/tests/functional/substrlval.asm b/tests/functional/substrlval.asm index d5d817aeb..c1431b10d 100644 --- a/tests/functional/substrlval.asm +++ b/tests/functional/substrlval.asm @@ -58,6 +58,7 @@ __LABEL1: DEFW 0001h DEFB 7Ah #line 1 "letsubstr.asm" + ; Substring assigment eg. LET a$(p0 TO p1) = "xxxx" ; HL = Start of string ; TOP of the stack -> p1 (16 bit, unsigned) @@ -68,6 +69,7 @@ __LABEL1: ; TOP -3 B$ address #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -136,6 +138,7 @@ __LABEL1: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -535,7 +538,9 @@ __FREE_STR: #line 46 "substrlval.bas" #line 1 "loadstr.asm" + #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -604,6 +609,7 @@ __FREE_STR: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -682,9 +688,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -804,6 +810,7 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 47 "substrlval.bas" #line 1 "storestr.asm" + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -817,7 +824,9 @@ __LOADSTR: ; __FASTCALL__ entry #line 1 "strcpy.asm" + #line 1 "realloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/subu32c.asm b/tests/functional/subu32c.asm index 8f774b4d8..ba654bcb5 100644 --- a/tests/functional/subu32c.asm +++ b/tests/functional/subu32c.asm @@ -68,6 +68,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sub32.asm" + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) @@ -97,6 +98,7 @@ __SUB32: ret #line 59 "subu32c.bas" #line 1 "swap32.asm" + ; Exchanges current DE HL with the ; ones in the stack diff --git a/tests/functional/usr0.asm b/tests/functional/usr0.asm index 3ae5048d3..02b31a4f5 100644 --- a/tests/functional/usr0.asm +++ b/tests/functional/usr0.asm @@ -39,11 +39,13 @@ __LABEL0: DEFW 0001h DEFB 41h #line 1 "print.asm" + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that #line 1 "sposn.asm" + ; Printing positioning library. PROC LOCAL ECHO_E @@ -77,6 +79,7 @@ __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. #line 6 "print.asm" #line 1 "cls.asm" + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen @@ -127,7 +130,9 @@ __CLS_SCR: #line 7 "print.asm" #line 1 "in_screen.asm" + #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -198,6 +203,7 @@ __OUT_OF_SCREEN_ERR: #line 8 "print.asm" #line 1 "table_jump.asm" + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a @@ -216,10 +222,12 @@ CALL_HL: #line 9 "print.asm" #line 1 "ink.asm" + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register #line 1 "const.asm" + ; Global constants P_FLAG EQU 23697 @@ -272,6 +280,7 @@ INK_TMP: #line 10 "print.asm" #line 1 "paper.asm" + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register @@ -320,6 +329,7 @@ PAPER_TMP: #line 11 "print.asm" #line 1 "flash.asm" + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -347,6 +357,7 @@ FLASH_TMP: #line 12 "print.asm" #line 1 "bright.asm" + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register @@ -376,12 +387,14 @@ BRIGHT_TMP: #line 13 "print.asm" #line 1 "over.asm" + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" -#line 4 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" @@ -440,7 +453,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/Users/boriel/Documents/src/zxbasic/library-asm/copy_attr.asm" +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -498,6 +511,7 @@ OVER_TMP: #line 14 "print.asm" #line 1 "inverse.asm" + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register @@ -531,6 +545,7 @@ INVERSE_TMP: #line 15 "print.asm" #line 1 "bold.asm" + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register @@ -563,6 +578,7 @@ BOLD_TMP: #line 16 "print.asm" #line 1 "italic.asm" + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register @@ -598,6 +614,7 @@ ITALIC_TMP: #line 17 "print.asm" #line 1 "attr.asm" + ; Attribute routines ; vim:ts=4:et:sw: @@ -1145,11 +1162,14 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes #line 26 "usr0.bas" #line 1 "printu16.asm" + #line 1 "printi16.asm" + #line 1 "printnum.asm" + __PRINTU_START: PROC @@ -1183,10 +1203,12 @@ __PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers #line 2 "printi16.asm" #line 1 "div16.asm" + ; 16 bit division and modulo functions ; for both signed and unsigned values #line 1 "neg16.asm" + ; Negates HL value (16 bit) __ABS16: bit 7, h @@ -1342,6 +1364,7 @@ __PRINTU_LOOP: #line 27 "usr0.bas" #line 1 "usr_str.asm" + ; This function just returns the address of the UDG of the given str. ; If the str is EMPTY or not a letter, 0 is returned and ERR_NR set ; to "A: Invalid Argument" @@ -1352,6 +1375,7 @@ __PRINTU_LOOP: #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1420,6 +1444,7 @@ __PRINTU_LOOP: ; They will be added automatically if needed. #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) diff --git a/tests/functional/valcrash2.asm b/tests/functional/valcrash2.asm index 7df6a11dd..b3b469c8f 100644 --- a/tests/functional/valcrash2.asm +++ b/tests/functional/valcrash2.asm @@ -47,12 +47,14 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "inkey.asm" + ; INKEY Function ; Returns a string allocated in dynamic memory ; containing the string. ; An empty string otherwise. #line 1 "alloc.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -121,6 +123,7 @@ __CALL_BACK__: ; They will be added automatically if needed. #line 1 "error.asm" + ; Simple error control routines ; vim:ts=4:et: @@ -162,6 +165,7 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -325,9 +329,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/Documents/src/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -459,6 +463,7 @@ __EMPTY_INKEY: #line 35 "valcrash2.bas" #line 1 "storef.asm" + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -490,7 +495,9 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL #line 36 "valcrash2.bas" #line 1 "strcat.asm" + #line 1 "strlen.asm" + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL @@ -634,7 +641,9 @@ __STRCATEND: #line 37 "valcrash2.bas" #line 1 "val.asm" + #line 1 "free.asm" + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -826,6 +835,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed #line 2 "val.asm" #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- diff --git a/tests/functional/while.asm b/tests/functional/while.asm index 063426459..2822e06bf 100644 --- a/tests/functional/while.asm +++ b/tests/functional/while.asm @@ -55,8 +55,11 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "ltf.asm" + #line 1 "u32tofreg.asm" + #line 1 "neg32.asm" + __ABS32: bit 7, d ret z @@ -180,6 +183,7 @@ __U32TOFREG_END: #line 1 "ftou32reg.asm" + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) @@ -256,6 +260,7 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A #line 3 "ltf.asm" #line 1 "stackf.asm" + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- @@ -328,6 +333,7 @@ __LTF: ; A < B #line 46 "while.bas" #line 1 "pushf.asm" + ; Routine to push Float pointed by HL ; Into the stack. Notice that the hl points to the last ; byte of the FP number. diff --git a/tests/functional/xor16.asm b/tests/functional/xor16.asm index 636f13fff..170d40922 100644 --- a/tests/functional/xor16.asm +++ b/tests/functional/xor16.asm @@ -52,8 +52,10 @@ __CALL_BACK__: DEFW 0 #line 1 "xor16.asm" + ; XOR16 implemented in XOR8.ASM file #line 1 "xor8.asm" + ; vim:ts=4:et: ; FASTCALL boolean xor 8 version. ; result in Accumulator (0 False, not 0 True) diff --git a/tests/functional/xor32.asm b/tests/functional/xor32.asm index 8722a149f..a8c81a5eb 100644 --- a/tests/functional/xor32.asm +++ b/tests/functional/xor32.asm @@ -67,12 +67,14 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "xor32.asm" + ; FASTCALL boolean xor 8 version. ; result in Accumulator (0 False, not 0 True) ; __FASTCALL__ version (operands: A, H) ; Performs 32bit xor 32bit and returns the boolean #line 1 "xor8.asm" + ; vim:ts=4:et: ; FASTCALL boolean xor 8 version. ; result in Accumulator (0 False, not 0 True) diff --git a/tests/functional/xor8.asm b/tests/functional/xor8.asm index 31546c1d5..080f3a266 100644 --- a/tests/functional/xor8.asm +++ b/tests/functional/xor8.asm @@ -43,6 +43,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "xor8.asm" + ; vim:ts=4:et: ; FASTCALL boolean xor 8 version. ; result in Accumulator (0 False, not 0 True) From 6edcad06cfd1de059d76dffe341e1a4382b8caf0 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Thu, 7 Sep 2017 23:27:30 +0200 Subject: [PATCH 046/247] bugfix: prevent error on wrong cmd params Sometimes when passing parameters like -o3 the compiler crashed. Fixed. --- api/options.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/api/options.py b/api/options.py index b64d57a22..9dc27b230 100644 --- a/api/options.py +++ b/api/options.py @@ -75,10 +75,12 @@ def value(self): @value.setter def value(self, value): - if self.type is not None: + if self.type is not None and not isinstance(value, self.type): try: value = eval(value) - except: + except TypeError: + pass + except ValueError: pass if value is not None and not isinstance(value, self.type): From 3a2c3993f4d68ea256442114a4cad6043d8d8c69 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 8 Sep 2017 22:13:00 +0200 Subject: [PATCH 047/247] add missing haplo font for radastan mode --- library/haplofnt.bin | Bin 0 -> 1152 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 library/haplofnt.bin diff --git a/library/haplofnt.bin b/library/haplofnt.bin new file mode 100644 index 0000000000000000000000000000000000000000..af728a8613c45377825d27ac892099119afa6be0 GIT binary patch literal 1152 zcmZXTftAA`3`5y~{kLQT?tclmzLqqJV`N!Y(lI{P8Xm)Qvfj>|Yiyo3nK>3)Jd4Sb z_vWddV#?BT@HxQnOB~|#AreoXIx}xc?F!$^hQo_0ick$J)eBu5)({o*Vr1H(@NMzj zaDYo*KDgwe-n)m&gD@wG!L*k z=@ZR(Q)h2q5$#p>|GZyZ=SaUBr~bSn`cf+)maon7`OceB$he5hqHhq}%)Z$?7dGB^ z9v?D;gQd3LsvGye(0t}C!uJ~|im<05j(%j?q5qNiqKsgE{8yW3X30#6>(JE`|4;tA zug=-EYIvY`{Wov6{AK)%^(XG=Vq*=yF?YQ5>%(caUk_JbYcTYwtgO CjR2(p literal 0 HcmV?d00001 From 9a2d41a995d44f7dcb8d74e662cd8cdfcbbc88f3 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 8 Sep 2017 22:11:08 +0200 Subject: [PATCH 048/247] allow incbin to behave like #include From now on, incbin file search behaves like include. --- api/utils.py | 10 ++++++++++ asmparse.py | 9 ++++++++- tests/functional/test_.py | 2 +- zxbpp.py | 14 ++++---------- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/api/utils.py b/api/utils.py index e872a96b2..6e0ef793f 100644 --- a/api/utils.py +++ b/api/utils.py @@ -5,6 +5,9 @@ from . import global_ from . import errmsg + +__all__ = ['read_txt_file', 'open_file', 'sanitize_filename'] + __doc__ = """Utils module contains many helpers for several task, like reading files or path management""" @@ -43,3 +46,10 @@ def open_file(fname, mode='rb', encoding='utf-8'): kwargs = {'encoding': encoding} return open(fname, mode, **kwargs) + + +def sanitize_filename(fname): + """ Given a file name (string) returns it with back-slashes reversed. + This is to make all BASIC programs compatible in all OSes + """ + return fname.replace('\\', '/') diff --git a/asmparse.py b/asmparse.py index 8b6438cfc..209acdaa6 100755 --- a/asmparse.py +++ b/asmparse.py @@ -23,6 +23,8 @@ from api.errmsg import syntax_error as error from api.errmsg import warning from api import global_ as gl +import api.utils +import zxbpp LEXER = asmlex.Lexer() @@ -830,7 +832,12 @@ def p_incbin(p): """ asm : INCBIN STRING """ try: - filecontent = open(p[2], 'rb').read() + fname = zxbpp.search_filename(p[2], p.lineno(2), local_first=True) + if not fname: + p[0] = None + return + with api.utils.open_file(fname, 'rb') as f: + filecontent = f.read() except IOError: error(p.lineno(2), "cannot read file '%s'" % p[2]) p[0] = None diff --git a/tests/functional/test_.py b/tests/functional/test_.py index ad42bd532..6e945a02d 100755 --- a/tests/functional/test_.py +++ b/tests/functional/test_.py @@ -73,7 +73,7 @@ >>> process_file('nosub.bas') nosub.bas:3: function 'nofunc' declared but not implemented >>> process_file('incbin0.asm') -incbin0.asm:3: cannot read file 'nofile.bin' +incbin0.asm:3: Error: file 'nofile.bin' not found >>> process_file('align3.asm') align3.asm:2: ALIGN value must be greater than 1 >>> process_file('rst0.asm') diff --git a/zxbpp.py b/zxbpp.py index aba611500..b2195311d 100755 --- a/zxbpp.py +++ b/zxbpp.py @@ -22,6 +22,7 @@ from api.config import OPTIONS from api import global_ +import api.utils from prepro.output import warning, error, CURRENT_FILE from prepro import DefinesTable, ID, MacroCall, Arg, ArgList from prepro.exceptions import PreprocError @@ -98,13 +99,6 @@ def get_include_path(): return result -def sanitize_file(fname): - """ Given a file name (string) returns it with back-slashes reversed. - This is to make all BASIC programs compatible in all OSes - """ - return fname.replace('\\', '/') - - def setMode(mode): global LEXER @@ -123,7 +117,7 @@ def search_filename(fname, lineno, local_first): If local_first is true, it will try first in the current directory of the file being analyzed. """ - fname = sanitize_file(fname) + fname = api.utils.sanitize_filename(fname) i_path = [CURRENT_DIR] + INCLUDEPATH if local_first else list(INCLUDEPATH) i_path.extend(OPTIONS.include_path.value.split(':') if OPTIONS.include_path.value else []) if os.path.isabs(fname): @@ -131,7 +125,7 @@ def search_filename(fname, lineno, local_first): return fname else: for dir_ in i_path: - path = sanitize_file(os.path.join(dir_, fname)) + path = api.utils.sanitize_filename(os.path.join(dir_, fname)) if os.path.exists(path): return path @@ -365,7 +359,7 @@ def p_line_file(p): def p_require_file(p): """ require : REQUIRE STRING NEWLINE """ - p[0] = ['#%s "%s"\n' % (p[1], sanitize_file(p[2]))] + p[0] = ['#%s "%s"\n' % (p[1], api.utils.sanitize_filename(p[2]))] def p_init(p): From 421cc91481f01d56b8188b2f9ebf738c04b8f5dd Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 8 Sep 2017 22:10:32 +0200 Subject: [PATCH 049/247] bugfix: binary test updating where not working Binary files do not need line transformations. --- tests/functional/tap_incbin.bas | 5 +++++ tests/functional/tap_incbin.tap | Bin 0 -> 1214 bytes tests/functional/test.py | 3 +++ 3 files changed, 8 insertions(+) create mode 100644 tests/functional/tap_incbin.bas create mode 100644 tests/functional/tap_incbin.tap diff --git a/tests/functional/tap_incbin.bas b/tests/functional/tap_incbin.bas new file mode 100644 index 000000000..6c35f50c1 --- /dev/null +++ b/tests/functional/tap_incbin.bas @@ -0,0 +1,5 @@ + +ASM +incbin "haplofnt.bin" +END ASM + diff --git a/tests/functional/tap_incbin.tap b/tests/functional/tap_incbin.tap new file mode 100644 index 0000000000000000000000000000000000000000..97a90a7d4bda809dae929fa4037f8f55d982bd04 GIT binary patch literal 1214 zcmZXUF;2rk6hv2o-UTOsk{i&|as~ucX(9>^kRq3$ju23ehreX4gbv zo!H-h=g*%%c5+q9#oN>C<81!&Jez-9mPJ{-e_q!8W_R4JckAm??rv7gLpfbz;V66u zt!Zl*#!_`(l^M#YE!~6h9oOVlJ%9;I%7ynKj6RM{>^_RXE3Y~-(}J31zA0-CPN)b1 zHCnD7rAr4jih`M9$)rQzmExg_LpbN*6Bj(H=gNUHc%1h&dk|Tb&&D;pTvEOH&D16^ zdsPQ2tqpE{#NEH}OB2&r3woM1rJ}((AoR3;ftj(z) The test is an error test and no compile filed should exist + if reBIN.match(tfname): # Binary files do not need updating + return + lines = get_file_lines(tfname, replace_regexp=pattern_, replace_what=ZXBASIC_ROOT, replace_with=_original_root) with zxb.api.utils.open_file(tfname, 'wt', encoding='utf-8') as f: From 6c8199ea70698247b8531dd9466847d0c808ea44 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 8 Sep 2017 22:16:48 +0200 Subject: [PATCH 050/247] =?UTF-8?q?Bump=20version:=201.6.11=20=E2=86=92=20?= =?UTF-8?q?1.6.12?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- ChangeLog | 6 ++++++ version.py | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 56d09473d..7724e9c6c 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,4 +1,4 @@ [bumpversion] -current_version = 1.6.11 +current_version = 1.6.12 files = version.py diff --git a/ChangeLog b/ChangeLog index e8bfdfafe..735c1b8ca 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,14 @@ +================================================================ +Changes from Version 1.6.11 to 1.6.12 ++ Adds missing default font (Haplo) for Radastan mode +! Bugfixes and little improvements + ================================================================ Changes from Version 1.6.10 to 1.6.11 ! Fix infinite recursive include in Windows (yes, win sucks) * Little optimizations in memset and rnd * Standarize file includes like in cpp + ================================================================ Changes from Version 1.6.9 to 1.6.10 + Added many more drawing primitives for Radastan Mode diff --git a/version.py b/version.py index d956d4c2d..e90219384 100755 --- a/version.py +++ b/version.py @@ -1 +1 @@ -VERSION = '1.6.11' +VERSION = '1.6.12' From aab55a07192eb6697a56127763d22f44b12887ee Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 8 Sep 2017 23:18:21 +0200 Subject: [PATCH 051/247] feature: add --strict type checking This enforces explicit type declaration. --- ChangeLog | 4 ++++ api/config.py | 1 + api/errmsg.py | 6 ++++++ tests/functional/strict.bas | 5 +++++ tests/functional/test_.py | 3 +++ zxb.py | 3 +++ zxbparser.py | 6 +++++- 7 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 tests/functional/strict.bas diff --git a/ChangeLog b/ChangeLog index 735c1b8ca..13b1b2aea 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +================================================================ +Changes from Version 1.6.11 to 1.6.12 ++ Adds strict mode for strict explicit type declaration checking + ================================================================ Changes from Version 1.6.11 to 1.6.12 + Adds missing default font (Haplo) for Radastan mode diff --git a/api/config.py b/api/config.py index 0923ceced..4b9d4ed87 100644 --- a/api/config.py +++ b/api/config.py @@ -66,6 +66,7 @@ def init(): OPTIONS.add_option('__DEFINES', dict, {}) OPTIONS.add_option('explicit', bool, False) OPTIONS.add_option('Sinclair', bool, False) + OPTIONS.add_option('strict', bool, False) # True to force type checking init() diff --git a/api/errmsg.py b/api/errmsg.py index 6798b4df7..35b61ebc7 100644 --- a/api/errmsg.py +++ b/api/errmsg.py @@ -145,3 +145,9 @@ def syntax_error_cant_convert_to_type(lineno, expr_str, type_): # ---------------------------------------- def syntax_error_is_a_sub_not_a_func(lineno, name): syntax_error(lineno, "'%s' is SUBROUTINE not a FUNCTION" % name) + + +# ---------------------------------------- +def syntax_error_undeclared_type(lineno): + syntax_error(lineno, "Strict mode: missing type declaration") +# ---------------------------------------- diff --git a/tests/functional/strict.bas b/tests/functional/strict.bas new file mode 100644 index 000000000..e88b8f935 --- /dev/null +++ b/tests/functional/strict.bas @@ -0,0 +1,5 @@ +#pragma strict=false +DIM b +#pragma strict=true +DIM a + diff --git a/tests/functional/test_.py b/tests/functional/test_.py index 6e945a02d..aa8714d93 100755 --- a/tests/functional/test_.py +++ b/tests/functional/test_.py @@ -88,6 +88,9 @@ asmprepro.asm:8: warning: Recursive inclusion asmprepro.asm:12: warning: Recursive inclusion asmprepro.asm:12: warning: Recursive inclusion +>>> process_file('strict.bas') +strict.bas:2: warning: Using default implicit type 'float' for 'b' +strict.bas:5: Strict mode: missing type declaration """ diff --git a/zxb.py b/zxb.py index 1070e41db..a2483cbf7 100755 --- a/zxb.py +++ b/zxb.py @@ -138,6 +138,8 @@ def main(args=None): help='Ignore case. Makes variable names are case insensitive') parser.add_argument('-I', '--include-path', type=str, default='', help='Add colon separated list of directories to add to include path. e.g. -I dir1:dir2') + parser.add_argument('--strict', action='store_true', + help='Enables strict mode. Force explicit type declaration') parser.add_argument('--version', action='version', version='%(prog)s {0}'.format(VERSION)) options = parser.parse_args(args=args) @@ -162,6 +164,7 @@ def main(args=None): OPTIONS.enableBreak.value = options.enable_break OPTIONS.explicit.value = options.explicit OPTIONS.memory_map.value = options.memory_map + OPTIONS.strict.value = options.strict if options.defines: for i in options.defines: diff --git a/zxbparser.py b/zxbparser.py index cdddff7ae..5a2a83eea 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -2703,7 +2703,11 @@ def p_function_body(p): def p_type_def_empty(p): """ typedef : """ # Epsilon. Defaults to float - p[0] = make_type(_TYPE(gl.DEFAULT_TYPE).name, p.lexer.lineno, implicit=True) + if OPTIONS.strict.value: # if strict mode, this is an error + api.errmsg.syntax_error_undeclared_type(p.lexer.lineno) + p[0] = make_type(_TYPE(gl.TYPE.unknown).name, p.lexer.lineno, implicit=True) + else: + p[0] = make_type(_TYPE(gl.DEFAULT_TYPE).name, p.lexer.lineno, implicit=True) def p_type_def(p): From e07962cf18598640ceddc3fe0e0c1a66bfb1943f Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 8 Sep 2017 23:36:03 +0200 Subject: [PATCH 052/247] bugfix: default file type is bin. Was being set to "bin". Also some deprecated test removed (cleanup) --- api/config.py | 2 +- tests/functional/runtime/ifgt8.bas | 21 --------------------- 2 files changed, 1 insertion(+), 22 deletions(-) delete mode 100644 tests/functional/runtime/ifgt8.bas diff --git a/api/config.py b/api/config.py index 4b9d4ed87..c99aec091 100644 --- a/api/config.py +++ b/api/config.py @@ -54,7 +54,7 @@ def init(): OPTIONS.add_option('use_loader', bool, False) # Whether to use a loader OPTIONS.add_option('autorun', bool, False) # Whether to add autostart code (needs basic loader = true) - OPTIONS.add_option('output_file_type', str, '"bin"') # bin, tap, tzx etc... + OPTIONS.add_option('output_file_type', str, 'bin') # bin, tap, tzx etc... OPTIONS.add_option('include_path', str, '') # Include path, like '/var/lib:/var/include' OPTIONS.add_option('memoryCheck', bool, False) diff --git a/tests/functional/runtime/ifgt8.bas b/tests/functional/runtime/ifgt8.bas deleted file mode 100644 index cc32aad43..000000000 --- a/tests/functional/runtime/ifgt8.bas +++ /dev/null @@ -1,21 +0,0 @@ - -DIM i, j, k as Byte - -i = 127 -DO - i = i + 1 - j = 127 - DO - j = j + 1 - IF i > j THEN - let k = i > j - if not k THEN - PRINT i; " !> "; j; " "; FLASH 1; INK 2; " ERROR " - STOP - END IF - END IF - LOOP UNTIL j = 127 -LOOP UNTIL i = 127 - -PRINT PAPER 4; INK 7; " SUCCESS "; PAPER 8; TAB 31 - From 6a48dcef059f3ca05ac8a2d8ff94cc95142ef452 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 9 Sep 2017 09:23:43 +0200 Subject: [PATCH 053/247] remove lines no longer needed Path initialization has been deprecated with the use of Tox and Pytest --- tests/api/__init__.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/api/__init__.py b/tests/api/__init__.py index b6ac7f1da..faa18be5b 100644 --- a/tests/api/__init__.py +++ b/tests/api/__init__.py @@ -1,10 +1,2 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- - -import sys -import os -import os.path - -# Initialization -path = os.path.realpath(os.path.join(os.path.join(os.path.dirname(__file__), os.path.pardir), os.path.pardir)) -sys.path.insert(0, path) From 27c1f1ed220edb1cb8f83e6bdd2307a4327dcd7b Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 9 Sep 2017 22:58:38 +0200 Subject: [PATCH 054/247] add test for options initialization --- api/options.py | 2 +- tests/api/test_config.py | 76 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 tests/api/test_config.py diff --git a/api/options.py b/api/options.py index 9dc27b230..cbb5860f4 100644 --- a/api/options.py +++ b/api/options.py @@ -118,7 +118,7 @@ def reset(self): if self.options is None: self.options = {} - for opt in list(self.options.keys()): + for opt in list(self.options.keys()): # converts to list since dict will change size during iteration self.remove_option(opt) def add_option(self, name, type_=None, default_value=None): diff --git a/tests/api/test_config.py b/tests/api/test_config.py new file mode 100644 index 000000000..f708d14b6 --- /dev/null +++ b/tests/api/test_config.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import unittest +import sys +from api import config +from api import global_ + + +class TestConfig(unittest.TestCase): + """ Tests api.config initialization + """ + def setUp(self): + config.OPTIONS.reset() + + def test_init(self): + config.init() + self.assertEqual(config.OPTIONS.Debug.value, 0) + self.assertEqual(config.OPTIONS.stdin.value, sys.stdin) + self.assertEqual(config.OPTIONS.stdout.value, sys.stdout) + self.assertEqual(config.OPTIONS.stderr.value, sys.stderr) + self.assertEqual(config.OPTIONS.optimization.value, global_.DEFAULT_OPTIMIZATION_LEVEL) + self.assertEqual(config.OPTIONS.case_insensitive.value, False) + self.assertEqual(config.OPTIONS.array_base.value, 0) + self.assertEqual(config.OPTIONS.byref.value, False) + self.assertEqual(config.OPTIONS.max_syntax_errors.value, global_.DEFAULT_MAX_SYNTAX_ERRORS) + self.assertEqual(config.OPTIONS.string_base.value, 0) + self.assertEqual(config.OPTIONS.memory_map.value, None) + self.assertEqual(config.OPTIONS.bracket.value, False) + self.assertEqual(config.OPTIONS.use_loader.value, False) + self.assertEqual(config.OPTIONS.autorun.value, False) + self.assertEqual(config.OPTIONS.output_file_type.value, 'bin') + self.assertEqual(config.OPTIONS.include_path.value, '') + self.assertEqual(config.OPTIONS.memoryCheck.value, False) + self.assertEqual(config.OPTIONS.strictBool.value, False) + self.assertEqual(config.OPTIONS.arrayCheck.value, False) + self.assertEqual(config.OPTIONS.enableBreak.value, False) + self.assertEqual(config.OPTIONS.emitBackend.value, False) + self.assertEqual(config.OPTIONS.arch.value, 'zx48k') + # private options that cannot be accessed with #pragma + self.assertEqual(config.OPTIONS.option('__DEFINES').value, {}) + self.assertEqual(config.OPTIONS.explicit.value, False) + self.assertEqual(config.OPTIONS.Sinclair.value, False) + self.assertEqual(config.OPTIONS.strict.value, False) + + def test_initted_values(self): + config.init() + self.assertEqual(sorted(config.OPTIONS.options.keys()), ['Debug', + 'Sinclair', + 'StdErrFileName', + '__DEFINES', + 'arch', + 'arrayCheck', + 'array_base', + 'autorun', + 'bracket', + 'byref', + 'case_insensitive', + 'emitBackend', + 'enableBreak', + 'explicit', + 'include_path', + 'inputFileName', + 'max_syntax_errors', + 'memoryCheck', + 'memory_map', + 'optimization', + 'outputFileName', + 'output_file_type', + 'stderr', + 'stdin', + 'stdout', + 'strict', + 'strictBool', + 'string_base', + 'use_loader']) From e502a6b89510e971e73ed9496fbfb686cf151647 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 10 Sep 2017 08:57:58 +0200 Subject: [PATCH 055/247] refact: rename function to ..explicit This function is used if option --explicit (not --strict) is used. --- api/check.py | 6 +++--- api/symboltable.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/api/check.py b/api/check.py index 99161064d..801076e1b 100644 --- a/api/check.py +++ b/api/check.py @@ -16,7 +16,7 @@ from .errmsg import syntax_error __all__ = ['check_type', - 'check_is_declared_strict', + 'check_is_declared_explicit', 'check_call_arguments', 'check_pending_calls', 'check_pending_labels', @@ -58,10 +58,10 @@ def check_type(lineno, type_list, arg): return False -def check_is_declared_strict(lineno, id_, classname='variable'): +def check_is_declared_explicit(lineno, id_, classname='variable'): """ Check if the current ID is already declared. If not, triggers a "undeclared identifier" error, - if the --strict command line flag is enabled (or #pragma + if the --explicit command line flag is enabled (or #pragma option strict is in use). If not in strict mode, passes it silently. diff --git a/api/symboltable.py b/api/symboltable.py index f6e8b8275..e59de8d4f 100644 --- a/api/symboltable.py +++ b/api/symboltable.py @@ -32,7 +32,7 @@ from .constants import TYPE from .check import is_number -from .check import check_is_declared_strict +from .check import check_is_declared_explicit # ---------------------------------------------------------------------- @@ -394,7 +394,7 @@ def access_id(self, id_, lineno, scope=None, default_type=None, default_class=CL default_type = symbols.TYPEREF(default_type, lineno, implicit=False) assert default_type is None or isinstance(default_type, symbols.TYPEREF) - if not check_is_declared_strict(lineno, id_): + if not check_is_declared_explicit(lineno, id_): return None result = self.get_entry(id_, scope) From b5a701488b7e38e04770a70b4253fb9a073303f7 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 10 Sep 2017 19:04:09 +0200 Subject: [PATCH 056/247] bugfix: correctly report strict mode errors The previous way failed for subs and sometimes did not report line numbers correctly. This new one, despite being a bit more complex, works ok and even report identifiers missing type declarations. --- api/check.py | 12 ++++++++++ api/errmsg.py | 8 +++++-- tests/functional/strict2.asm | 43 ++++++++++++++++++++++++++++++++++++ tests/functional/strict2.bas | 6 +++++ tests/functional/strict3.bas | 7 ++++++ tests/functional/strict4.bas | 10 +++++++++ tests/functional/strict5.bas | 7 ++++++ tests/functional/strict6.bas | 6 +++++ tests/functional/strict7.bas | 11 +++++++++ tests/functional/test_.py | 2 +- zxbparser.py | 11 ++++----- 11 files changed, 115 insertions(+), 8 deletions(-) create mode 100644 tests/functional/strict2.asm create mode 100644 tests/functional/strict2.bas create mode 100644 tests/functional/strict3.bas create mode 100644 tests/functional/strict4.bas create mode 100644 tests/functional/strict5.bas create mode 100644 tests/functional/strict6.bas create mode 100644 tests/functional/strict7.bas diff --git a/api/check.py b/api/check.py index 801076e1b..5ac94aed2 100644 --- a/api/check.py +++ b/api/check.py @@ -13,10 +13,12 @@ from . import global_ from .constants import CLASS from .constants import SCOPE +import api.errmsg from .errmsg import syntax_error __all__ = ['check_type', 'check_is_declared_explicit', + 'check_type_is_explicit', 'check_call_arguments', 'check_pending_calls', 'check_pending_labels', @@ -73,6 +75,16 @@ def check_is_declared_explicit(lineno, id_, classname='variable'): return entry is not None # True if declared +def check_type_is_explicit(lineno, id_, type_): + if not config.OPTIONS.strict.value: + return # not in strict mode. Nothing to do + + from symbols.type_ import SymbolTYPE + assert isinstance(type_, SymbolTYPE) + if type_.implicit: + api.errmsg.syntax_error_undeclared_type(lineno, id_) + + def check_call_arguments(lineno, id_, args): """ Check arguments against function signature. diff --git a/api/errmsg.py b/api/errmsg.py index 35b61ebc7..991114a83 100644 --- a/api/errmsg.py +++ b/api/errmsg.py @@ -45,6 +45,10 @@ def warning(lineno, msg): def warning_implicit_type(lineno, id_, type_=None): """ Warning: Using default implicit type 'x' """ + if OPTIONS.strict.value: + syntax_error_undeclared_type(lineno, id_) + return + if type_ is None: type_ = global_.DEFAULT_TYPE @@ -148,6 +152,6 @@ def syntax_error_is_a_sub_not_a_func(lineno, name): # ---------------------------------------- -def syntax_error_undeclared_type(lineno): - syntax_error(lineno, "Strict mode: missing type declaration") +def syntax_error_undeclared_type(lineno, id_): + syntax_error(lineno, "strict mode: missing type declaration for '%s'" % id_) # ---------------------------------------- diff --git a/tests/functional/strict2.asm b/tests/functional/strict2.asm new file mode 100644 index 000000000..d562c4692 --- /dev/null +++ b/tests/functional/strict2.asm @@ -0,0 +1,43 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +_anysub: + push ix + ld ix, 0 + add ix, sp +_anysub__leave: + ld sp, ix + pop ix + ret + +ZXBASIC_USER_DATA: + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/strict2.bas b/tests/functional/strict2.bas new file mode 100644 index 000000000..23dec08a1 --- /dev/null +++ b/tests/functional/strict2.bas @@ -0,0 +1,6 @@ +#pragma strict=true + +sub anysub() +end sub + + diff --git a/tests/functional/strict3.bas b/tests/functional/strict3.bas new file mode 100644 index 000000000..db40491f4 --- /dev/null +++ b/tests/functional/strict3.bas @@ -0,0 +1,7 @@ +#pragma strict=true + +REM error, anyfunc has no type +function anyfunc() +end function + + diff --git a/tests/functional/strict4.bas b/tests/functional/strict4.bas new file mode 100644 index 000000000..d981dae49 --- /dev/null +++ b/tests/functional/strict4.bas @@ -0,0 +1,10 @@ +#pragma strict=true + +SUB goodsub(a as Ubyte, b as UInteger) +END SUB + +REM no error: no param missing type +REM error: param missing type +SUB anysub(a as UByte, b) +END SUB + diff --git a/tests/functional/strict5.bas b/tests/functional/strict5.bas new file mode 100644 index 000000000..89cd93aed --- /dev/null +++ b/tests/functional/strict5.bas @@ -0,0 +1,7 @@ +#pragma strict=true + +DIM a, b as Byte +DIM c +DIM e, f + + diff --git a/tests/functional/strict6.bas b/tests/functional/strict6.bas new file mode 100644 index 000000000..acaafc041 --- /dev/null +++ b/tests/functional/strict6.bas @@ -0,0 +1,6 @@ + +#pragma strict=true + +DIM a = 5 +CONST b = 6 + diff --git a/tests/functional/strict7.bas b/tests/functional/strict7.bas new file mode 100644 index 000000000..643a03694 --- /dev/null +++ b/tests/functional/strict7.bas @@ -0,0 +1,11 @@ + + +DIM a(1 TO 3) + +#pragma strict=true + +DIM b(1 TO 3) + +DIM c(1 TO 3) => {1, 2, 3} + + diff --git a/tests/functional/test_.py b/tests/functional/test_.py index aa8714d93..dba5b699e 100755 --- a/tests/functional/test_.py +++ b/tests/functional/test_.py @@ -90,7 +90,7 @@ asmprepro.asm:12: warning: Recursive inclusion >>> process_file('strict.bas') strict.bas:2: warning: Using default implicit type 'float' for 'b' -strict.bas:5: Strict mode: missing type declaration +strict.bas:4: strict mode: missing type declaration for 'a' """ diff --git a/zxbparser.py b/zxbparser.py index 5a2a83eea..7aa1bdf25 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -2571,6 +2571,9 @@ def p_function_header(p): p[0] = None return + if FUNCTION_LEVEL[-1].kind == KIND.function: + api.check.check_type_is_explicit(p[0].entry.lineno, p[0].entry.name, p[3]) + if p[0].entry.convention == CONVENTION.fastcall and len(p[2]) > 1: kind = 'SUB' if FUNCTION_LEVEL[-1].kind == KIND.sub else 'FUNCTION' warning(p.lineno(4), "%s '%s' declared as FASTCALL with %i parameters" % (kind, p[0].entry.name, @@ -2671,6 +2674,8 @@ def p_param_definition(p): def p_param_def_type(p): """ param_def : ID typedef """ + if p[2] is not None: + api.check.check_type_is_explicit(p.lineno(1), p[1], p[2]) p[0] = make_param_decl(p[1], p.lineno(1), p[2]) @@ -2703,11 +2708,7 @@ def p_function_body(p): def p_type_def_empty(p): """ typedef : """ # Epsilon. Defaults to float - if OPTIONS.strict.value: # if strict mode, this is an error - api.errmsg.syntax_error_undeclared_type(p.lexer.lineno) - p[0] = make_type(_TYPE(gl.TYPE.unknown).name, p.lexer.lineno, implicit=True) - else: - p[0] = make_type(_TYPE(gl.DEFAULT_TYPE).name, p.lexer.lineno, implicit=True) + p[0] = make_type(_TYPE(gl.DEFAULT_TYPE).name, p.lexer.lineno, implicit=True) def p_type_def(p): From 47637cd035406cde9fb3400854e8c857f5e29c19 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 10 Sep 2017 23:14:29 +0200 Subject: [PATCH 057/247] add #error and #warning capabilities Now zxbpp allows #error and #warning lines --- tests/functional/prepro76.bi | 3 +++ tests/functional/prepro77.bi | 3 +++ tests/functional/prepro77.out | 3 +++ zxbpp.py | 20 ++++++++++++++++++++ zxbpplex.py | 29 +++++++++++++++++++++++++---- 5 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 tests/functional/prepro76.bi create mode 100644 tests/functional/prepro77.bi create mode 100644 tests/functional/prepro77.out diff --git a/tests/functional/prepro76.bi b/tests/functional/prepro76.bi new file mode 100644 index 000000000..35cb2a60b --- /dev/null +++ b/tests/functional/prepro76.bi @@ -0,0 +1,3 @@ + +#error this is an intended error + diff --git a/tests/functional/prepro77.bi b/tests/functional/prepro77.bi new file mode 100644 index 000000000..15fbcdecc --- /dev/null +++ b/tests/functional/prepro77.bi @@ -0,0 +1,3 @@ + +#warning this is an intended warning + diff --git a/tests/functional/prepro77.out b/tests/functional/prepro77.out new file mode 100644 index 000000000..252ff806c --- /dev/null +++ b/tests/functional/prepro77.out @@ -0,0 +1,3 @@ +#line 1 "prepro77.bi" + + diff --git a/zxbpp.py b/zxbpp.py index b2195311d..5a085b129 100755 --- a/zxbpp.py +++ b/zxbpp.py @@ -199,6 +199,8 @@ def p_program(p): | ifdef | require | pragma + | errormsg + | warningmsg """ p[0] = p[1] @@ -229,6 +231,8 @@ def p_program_char(p): | program ifdef | program require | program pragma + | program errormsg + | program warningmsg """ p[0] = p[1] + p[2] @@ -378,6 +382,22 @@ def p_undef(p): p[0] = [] +def p_errormsg(p): + """ errormsg : ERROR STRING + """ + if ENABLED: + error(p.lineno(1), p[2]) + p[0] = [] + + +def p_warningmsg(p): + """ warningmsg : WARNING STRING + """ + if ENABLED: + warning(p.lineno(1), p[2]) + p[0] = [] + + def p_define(p): """ define : DEFINE ID params defs """ diff --git a/zxbpplex.py b/zxbpplex.py index 65dd81b1c..223a4f418 100755 --- a/zxbpplex.py +++ b/zxbpplex.py @@ -33,7 +33,8 @@ ('comment', 'exclusive'), ('asm', 'exclusive'), ('asmcomment', 'exclusive'), - ('if', 'exclusive') + ('if', 'exclusive'), + ('msg', 'exclusive') ) _tokens = ('STRING', 'TOKEN', 'NEWLINE', '_ENDFILE_', 'FILENAME', 'ID', @@ -55,6 +56,8 @@ 'line': 'LINE', 'require': 'REQUIRE', 'pragma': 'PRAGMA', + 'error': 'ERROR', + 'warning': 'WARNING' } # List of token names. @@ -172,6 +175,13 @@ def t_comment_endBlock(self, t): if not self.__COMMENT_LEVEL: t.lexer.begin('INITIAL') + def t_msg_STRING(self, t): + r'.*\n' + t.lexer.lineno += 1 + t.lexer.begin('INITIAL') + t.value = t.value.strip() # remove newline an spaces + return t + # Any other character is ignored until EOL def t_singlecomment_comment_Skip(self, t): r'.' @@ -222,6 +232,9 @@ def t_prepro_ID(self, t): if t.type == 'IF': t.lexer.begin('if') + if t.type in ('ERROR', 'WARNING'): + t.lexer.begin('msg') + if t.type == 'ID' and self.expectingDirective: self.error("invalid directive #%s" % t.value) @@ -352,16 +365,24 @@ def t_prepro_FILENAME(self, t): t.value = t.value[1:-1] # Remove quotes return t - def t_INITIAL_defargs_defargsopt_prepro_define_defexpr_pragma_comment_singlecomment_asm_asmcomment_if_ANY(self, t): + def t_INITIAL_defargs_defargsopt_prepro_define_defexpr_pragma_comment_singlecomment_ANY(self, t): r'.' self.error("illegal preprocessor character '%s'" % t.value[0]) - def t_INITIAL_defargs_defargsopt_prepro_define_defexpr_pragma_comment_singlecomment_asm_asmcomment_if_error(self, - t): + def t_INITIAL_defargs_defargsopt_prepro_define_defexpr_pragma_comment_singlecomment_error(self, t): """ error handling rule. Should never happen! """ pass # The lexer will raise an exception here. This is intended + def t_asm_asmcomment_if_ANY(self, t): + r'.' + self.error("illegal preprocessor character '%s'" % t.value[0]) + + def t_asm_asmcomment_if_msg_error(self, t): + """ error handling rule. Should never happen! + """ + pass + def put_current_line(self, prefix='', suffix=''): """ Returns line and file for include / end of include sequences. """ From df62e8b8c2899553a216e26583612c316a21f760 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 11 Sep 2017 23:44:31 +0200 Subject: [PATCH 058/247] Changelog --- ChangeLog | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 13b1b2aea..81aa39309 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ ================================================================ -Changes from Version 1.6.11 to 1.6.12 -+ Adds strict mode for strict explicit type declaration checking +Changes from Version 1.6.12 to 1.6.13 +! Fixes and improves strict mode checking ++ Adds #error and #warning directives ================================================================ Changes from Version 1.6.11 to 1.6.12 From 3c03796e496015c81ddc7aeea5d9cebbae4ac222 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 12 Sep 2017 21:44:36 +0200 Subject: [PATCH 059/247] bugfix: do not emit CLEAR if low org When creating a program with ORG < 16364, the BASIC loader, if requested should not contain a CLEAR line. --- asmparse.py | 3 ++- tests/functional/tap_00.tap | Bin 1212 -> 1281 bytes tests/functional/tap_01.bas | 4 ++++ tests/functional/tap_01.tap | Bin 0 -> 111 bytes tests/functional/tap_incbin.tap | Bin 1214 -> 1283 bytes tests/functional/test.py | 2 +- tests/functional/tzx_00.tzx | Bin 1228 -> 1303 bytes 7 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 tests/functional/tap_01.bas create mode 100644 tests/functional/tap_01.tap diff --git a/asmparse.py b/asmparse.py index 209acdaa6..9ee8ee8ce 100755 --- a/asmparse.py +++ b/asmparse.py @@ -1444,7 +1444,8 @@ def generate_binary(outputfname, format_, progname=''): import basic # Minimalist basic tokenizer program = basic.Basic() - program.add_line([['CLEAR', org - 1]]) + if org > 16383: # Only for zx48k: CLEAR if below 16383 + program.add_line([['CLEAR', org - 1]]) program.add_line([['LOAD', '""', program.token('CODE')]]) if OPTIONS.autorun.value: diff --git a/tests/functional/tap_00.tap b/tests/functional/tap_00.tap index 77269b08368376a2aeb1bb53eb4cddb560198f84..2506772102b7bd61d2762d26f5aff9b91892307e 100644 GIT binary patch delta 77 zcmdnP*~sN8%)r2qlb@K9TBHC3It+{qIt&7O4F4Ipcp3g08=0G#^D!{|uV>(85MgC_ cucWk|mqCt?;pYL6lm$?Vp@D(7e#0IX0FB)dZ2$lO delta 8 PcmZqV+QYfgbq@;w4f+EI diff --git a/tests/functional/tap_01.bas b/tests/functional/tap_01.bas new file mode 100644 index 000000000..9aadbfa2a --- /dev/null +++ b/tests/functional/tap_01.bas @@ -0,0 +1,4 @@ +#pragma org=0 + +DIM a as UByte = 1 + diff --git a/tests/functional/tap_01.tap b/tests/functional/tap_01.tap new file mode 100644 index 0000000000000000000000000000000000000000..62471c0a6da32ad267bf97b2eb78e70d5bff28b8 GIT binary patch literal 111 zcmWe;U|`6}PfSTIQUC&R21W*P1_4Qi{|sEL4DXec*7Guma54NmV891d$H2h5Qka2( zxg@b5-oQ`~NU4DY8?I_F{QrFS>EEX}pWaktV6aqDX7~-HU3@=lDKq@M`S9l7hj$(85MgC_ cucWk|mqCt?;pYL6lm$?Vp@D(7e#1T%0FMz7a{vGU delta 8 PcmZqX+Q+%kbsq}=4jKau diff --git a/tests/functional/test.py b/tests/functional/test.py index 2f9d5caee..f38f6bf86 100755 --- a/tests/functional/test.py +++ b/tests/functional/test.py @@ -210,7 +210,7 @@ def _get_testbas_options(fname): tfname = os.path.join(TEMP_DIR, getName(fname) + os.extsep + ext) else: tfname = getName(fname) + os.extsep + ext - options.extend(['--%s' % ext, fname, '-o', tfname] + prep) + options.extend(['--%s' % ext, fname, '-o', tfname, '-a', '-B'] + prep) else: ext = 'asm' if not UPDATE: diff --git a/tests/functional/tzx_00.tzx b/tests/functional/tzx_00.tzx index ec3f81df1848d7a2a1dc7132861721d5c17d3e22..b0cf1539cb1958325a289c275d131ffa4d9905d9 100644 GIT binary patch delta 94 zcmX@ZIh`vsDk3DYAXQO{QB>dsvoHe#Lr#8TN@|e;5a=*4GUzY}0LAqf{xfj#GW<0* sGB-2lV_^7S&%nzd!piVoNohSVgB%~j&jTPS3!oH30|RgUMy^9F05WA3Hvj+t delta 19 acmbQvb%v8GDk3DYAXQO{QFLSIAr=5Tk_FlT From 3851e1468ddb45050dd908ec04d5a3e41070a694 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 17 Sep 2017 12:51:25 +0200 Subject: [PATCH 060/247] bugfix: fix a bug in the grammar The sequence func:func was not allowed. Fixed. --- tests/functional/idco.asm | 46 +++++++++++++++++++++++++++++++++++++++ tests/functional/idco.bas | 8 +++++++ zxbparser.py | 1 + 3 files changed, 55 insertions(+) create mode 100644 tests/functional/idco.asm create mode 100644 tests/functional/idco.bas diff --git a/tests/functional/idco.asm b/tests/functional/idco.asm new file mode 100644 index 000000000..c4357ed5b --- /dev/null +++ b/tests/functional/idco.asm @@ -0,0 +1,46 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call _p + call _p + call _p + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +_p: + push ix + ld ix, 0 + add ix, sp +_p__leave: + ld sp, ix + pop ix + ret + +ZXBASIC_USER_DATA: + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/idco.bas b/tests/functional/idco.bas new file mode 100644 index 000000000..22bdea13c --- /dev/null +++ b/tests/functional/idco.bas @@ -0,0 +1,8 @@ + +SUB p() +END sub + +p + +p:p + diff --git a/zxbparser.py b/zxbparser.py index 7aa1bdf25..331feb696 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -867,6 +867,7 @@ def p_statement_call(p): """ statement : ID arg_list NEWLINE | ID arg_list CO | ID NEWLINE + | ID CO """ if p[2] is None: p[0] = None From a2c6d31fc7c6ca1928cbc896fc10e0432fc8faa5 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 17 Sep 2017 20:10:13 +0200 Subject: [PATCH 061/247] bugfix: -e param now works When using test.py from the command line, the param -e (--stderr) was being ignored regardless of its value. Now it correcly makes the error messages to show up if -e is specified. --- tests/functional/test.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/functional/test.py b/tests/functional/test.py index f38f6bf86..f0f7a8cc1 100755 --- a/tests/functional/test.py +++ b/tests/functional/test.py @@ -43,7 +43,8 @@ FOUT = sys.stdout # Output file. By default stdout but can be captured changing this TEMP_DIR = None QUIET = False # True so suppress output (useful for testing) -STDERR = '/dev/stderr' +DEFAULT_STDERR = '/dev/stderr' +STDERR = None INLINE = True # Set to false to use system Shell @@ -464,6 +465,7 @@ def main(argv=None): global QUIET global STDERR global INLINE + global CLOSE_STDERR parser = argparse.ArgumentParser(description='Test compiler output against source code samples') parser.add_argument('-d', '--show-diff', action='store_true', help='Shows output difference on failure') @@ -475,11 +477,16 @@ def main(argv=None): parser.add_argument('--tmp-dir', type=str, default=TEMP_DIR, help='Temporary directory for tests generation') parser.add_argument('FILES', nargs='+', type=str, help='List of files to be processed') parser.add_argument('-q', '--quiet', action='store_true', help='Run quietly, suppressing normal output') - parser.add_argument('-e', '--stderr', type=str, default=STDERR, help='File for stderr messages') + parser.add_argument('-e', '--stderr', type=str, default=None, help='File for stderr messages') parser.add_argument('-S', '--use-shell', action='store_true', help='Use system shell for test instead of inline') args = parser.parse_args(argv) STDERR = args.stderr + if STDERR: + CLOSE_STDERR = False + else: + STDERR = DEFAULT_STDERR + INLINE = not args.use_shell temp_dir_created = False From d42f558f4fadb1ee0f4201944ffacab0372f2b81 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 17 Sep 2017 20:12:07 +0200 Subject: [PATCH 062/247] Allow calling SUB without parenthesis. This will allow to do both: DRAW x, y or DRAW(x, y) in the source code. Which means now ZX Basic can be expanded! (well, sort of) Now the lexer does tie-in on ID to detect array variables. It will return ARRAY_ID instead of ID if an array variable name is detected. This allows more powerful grammar constructs. Test added and updated. --- tests/functional/array08.asm | 1126 +++++++++++++++++++++++++++ tests/functional/array08.bas | 6 + tests/functional/array12.asm | 1349 +++++++++++++++++++++++++++++++++ tests/functional/array12.bas | 6 + tests/functional/lcd6.asm | 109 +++ tests/functional/lcd6.bas | 5 + tests/functional/ltee10.asm | 277 +++++++ tests/functional/ltee10.bas | 7 + tests/functional/subparam.asm | 55 ++ tests/functional/subparam.bas | 9 + zxblex.py | 6 + zxbparser.py | 152 ++-- 12 files changed, 3061 insertions(+), 46 deletions(-) create mode 100644 tests/functional/array08.asm create mode 100644 tests/functional/array08.bas create mode 100644 tests/functional/array12.asm create mode 100644 tests/functional/array12.bas create mode 100644 tests/functional/lcd6.asm create mode 100644 tests/functional/lcd6.bas create mode 100644 tests/functional/ltee10.asm create mode 100644 tests/functional/ltee10.bas create mode 100644 tests/functional/subparam.asm create mode 100644 tests/functional/subparam.bas diff --git a/tests/functional/array08.asm b/tests/functional/array08.asm new file mode 100644 index 000000000..1de8e36eb --- /dev/null +++ b/tests/functional/array08.asm @@ -0,0 +1,1126 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld hl, (_b) + push hl + ld hl, _a + call __ARRAY + ld de, (_s) + call __STORE_STR + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "array.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; ------------------------------------------------------------------- + ; Simple array Index routine + ; Number of total indexes dimensions - 1 at beginning of memory + ; HL = Start of array memory (First two bytes contains N-1 dimensions) + ; Dimension values on the stack, (top of the stack, highest dimension) + ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> + + ; For any array of N dimension A(aN-1, ..., a1, a0) + ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as + ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] +; What I will do here is to calculate the following sequence: + ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... + + +#line 1 "mul16.asm" + +__MUL16: ; Mutiplies HL with the last value stored into de stack + ; Works for both signed and unsigned + + PROC + + LOCAL __MUL16LOOP + LOCAL __MUL16NOADD + + ex de, hl + pop hl ; Return address + ex (sp), hl ; CALLEE caller convention + +;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand + ;; ld c, h + ;; ld a, l ; C,A => 1st Operand + ;; + ;; ld hl, 0 ; Accumulator + ;; ld b, 16 + ;; +;;__MUL16LOOP: + ;; sra c ; C,A >> 1 (Arithmetic) + ;; rra + ;; + ;; jr nc, __MUL16NOADD + ;; add hl, de + ;; +;;__MUL16NOADD: + ;; sla e + ;; rl d + ;; + ;; djnz __MUL16LOOP + +__MUL16_FAST: + ld b, 16 + ld a, d + ld c, e + ex de, hl + ld hl, 0 + +__MUL16LOOP: + add hl, hl ; hl << 1 + sla c + rla ; a,c << 1 + jp nc, __MUL16NOADD + add hl, de + +__MUL16NOADD: + djnz __MUL16LOOP + + ret ; Result in hl (16 lower bits) + + ENDP + +#line 20 "array.asm" + +#line 24 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" + +__ARRAY: + PROC + + LOCAL LOOP + LOCAL ARRAY_END + LOCAL RET_ADDRESS ; Stores return address + + ex (sp), hl ; Return address in HL, array address in the stack + ld (RET_ADDRESS + 1), hl ; Stores it for later + + exx + pop hl ; Will use H'L' as the pointer + ld c, (hl) ; Loads Number of dimensions from (hl) + inc hl + ld b, (hl) + inc hl ; Ready + exx + + ld hl, 0 ; BC = Offset "accumulator" + +#line 48 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" + +LOOP: + pop bc ; Get next index (Ai) from the stack + +#line 60 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" + + add hl, bc ; Adds current index + + exx ; Checks if B'C' = 0 + ld a, b ; Which means we must exit (last element is not multiplied by anything) + or c + jr z, ARRAY_END ; if B'Ci == 0 we are done + + ld e, (hl) ; Loads next dimension into D'E' + inc hl + ld d, (hl) + inc hl + push de + dec bc ; Decrements loop counter + exx + pop de ; DE = Max bound Number (i-th dimension) + +#line 80 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" + ;call __MUL16_FAST ; HL *= DE + call __FNMUL +#line 86 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" + jp LOOP + +ARRAY_END: + ld e, (hl) + inc hl + ld d, c ; C = 0 => DE = E = Element size + push hl + push de + exx + +#line 100 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" + LOCAL ARRAY_SIZE_LOOP + + ex de, hl + ld hl, 0 + pop bc + ld b, c +ARRAY_SIZE_LOOP: + add hl, de + djnz ARRAY_SIZE_LOOP + + ;; Even faster + ;pop bc + + ;ld d, h + ;ld e, l + + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, hl + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, hl + ;dec c + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, de + ;__ARRAY_FIN: +#line 131 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" + + pop de + add hl, de ; Adds element start + +RET_ADDRESS: + ld de, 0 + push de + ret ; HL = (Start of Elements + Offset) + + ;; Performs a faster multiply for little 16bit numbs + LOCAL __FNMUL, __FNMUL2 + +__FNMUL: + xor a + or d + jp nz, __MUL16_FAST + + or e + ex de, hl + ret z + + cp 33 + jp nc, __MUL16_FAST + + ld b, l + ld l, h ; HL = 0 + +__FNMUL2: + add hl, de + djnz __FNMUL2 + ret + + ENDP + +#line 24 "array08.bas" +#line 1 "storestr.asm" + +; vim:ts=4:et:sw=4 + ; Stores value of current string pointed by DE register into address pointed by HL + ; Returns DE = Address pointer (&a$) + ; Returns HL = HL (b$ => might be needed later to free it from the heap) + ; + ; e.g. => HL = _variableName (DIM _variableName$) + ; DE = Address into the HEAP + ; + ; This function will resize (REALLOC) the space pointed by HL + ; before copying the content of b$ into a$ + + +#line 1 "strcpy.asm" + +#line 1 "realloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 70 "realloc.asm" +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 70 "alloc.asm" + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/Users/boriel/src/zxbasic/zxbasic/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/Users/boriel/src/zxbasic/zxbasic/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 71 "realloc.asm" +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 72 "realloc.asm" + + + ; --------------------------------------------------------------------- + ; MEM_REALLOC + ; Reallocates a block of memory in the heap. + ; + ; Parameters + ; HL = Pointer to the original block + ; BC = New Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; +; Notes: + ; If BC = 0, the block is freed, otherwise + ; the content of the original block is copied to the new one, and + ; the new size is adjusted. If BC < original length, the content + ; will be truncated. Otherwise, extra block content might contain + ; memory garbage. + ; + ; --------------------------------------------------------------------- +__REALLOC: ; Reallocates block pointed by HL, with new length BC + PROC + + LOCAL __REALLOC_END + + ld a, h + or l + jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc + + ld e, (hl) + inc hl + ld d, (hl) ; DE = First 2 bytes of HL block + + push hl + exx + pop de + inc de ; DE' <- HL + 2 + exx ; DE' <- HL (Saves current pointer into DE') + + dec hl ; HL = Block start + + push de + push bc + call __MEM_FREE ; Frees current block + pop bc + push bc + call __MEM_ALLOC ; Gets a new block of length BC + pop bc + pop de + + ld a, h + or l + ret z ; Return if HL == NULL (No memory) + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Recovers first 2 bytes in HL + + dec bc + dec bc ; BC = BC - 2 (Two bytes copied) + + ld a, b + or c + jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) + + exx + push de + exx + pop de ; DE <- DE' ; Start of remaining block + + push hl ; Saves current Block + 2 start + ex de, hl ; Exchanges them: DE is destiny block + ldir ; Copies BC Bytes + pop hl ; Recovers Block + 2 start + +__REALLOC_END: + + dec hl ; Set HL + dec hl ; To begin of block + ret + + ENDP + +#line 2 "strcpy.asm" + + ; String library + + +__STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) + PROC + + LOCAL __STRREALLOC + LOCAL __STRCONTINUE + LOCAL __B_IS_NULL + LOCAL __NOTHING_TO_COPY + + ld b, d + ld c, e + ld a, b + or c + jr z, __B_IS_NULL + + ex de, hl + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(b$) + ex de, hl ; DE = &b$ + +__B_IS_NULL: ; Jumps here if B$ pointer is NULL + inc bc + inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) + + push de + push hl + + ld a, h + or l + jr z, __STRREALLOC + + dec hl + ld d, (hl) + dec hl + ld e, (hl) ; DE = MEMBLOCKSIZE(a$) + dec de + dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) + + ld h, b + ld l, c ; HL = LEN(b$) + 2 => Minimum block size required + ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 + + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) + sbc hl, de ; Carry if len(b$) > Blocklen(a$) + jr c, __STRREALLOC ; No need to realloc + ; Need to reallocate at least to len(b$) + 2 + ex de, hl ; DE = Remaining bytes in a$ mem block. + ld hl, 4 + sbc hl, de ; if remaining bytes < 4 we can continue + jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes + +__STRREALLOC: + pop hl + call __REALLOC ; Returns in HL a new pointer with BC bytes allocated + push hl + +__STRCONTINUE: ; Pops hl and de SWAPPED + pop de ; DE = &a$ + pop hl ; HL = &b$ + + ld a, d ; Return if not enough memory for new length + or e + ret z ; Return if DE == NULL (0) + +__STRCPY: ; Copies string pointed by HL into string pointed by DE + ; Returns DE as HL (new pointer) + ld a, h + or l + jr z, __NOTHING_TO_COPY + ld c, (hl) + inc hl + ld b, (hl) + dec hl + inc bc + inc bc + push de + ldir + pop hl + ret + +__NOTHING_TO_COPY: + ex de, hl + ld (hl), e + inc hl + ld (hl), d + dec hl + ret + + ENDP + +#line 14 "storestr.asm" + +__PISTORE_STR: ; Indirect assignement at (IX + BC) + push ix + pop hl + add hl, bc + +__ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + +__STORE_STR: + push de ; Pointer to b$ + push hl ; Array pointer to variable memory address + + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation + ex de, hl ; DE = new address of a$ + pop hl ; Recover variable memory address pointer + + ld (hl), e + inc hl + ld (hl), d ; Stores a$ ptr into elemem ptr + + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) + ret + +#line 25 "array08.bas" + +ZXBASIC_USER_DATA: +_b: + DEFB 00, 00 +_s: + DEFB 00, 00 +_a: + DEFW 0000h + DEFB 02h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/array08.bas b/tests/functional/array08.bas new file mode 100644 index 000000000..7f39002b1 --- /dev/null +++ b/tests/functional/array08.bas @@ -0,0 +1,6 @@ +DIM a$(10) +DIM b as Uinteger +DIM s as String + +a$(b) = s + diff --git a/tests/functional/array12.asm b/tests/functional/array12.asm new file mode 100644 index 000000000..7c1d70835 --- /dev/null +++ b/tests/functional/array12.asm @@ -0,0 +1,1349 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld hl, (_b) + push hl + ld hl, (_b) + push hl + ld hl, _a + call __ARRAY + ld de, (_s) + call __STORE_STR + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "array.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; ------------------------------------------------------------------- + ; Simple array Index routine + ; Number of total indexes dimensions - 1 at beginning of memory + ; HL = Start of array memory (First two bytes contains N-1 dimensions) + ; Dimension values on the stack, (top of the stack, highest dimension) + ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> + + ; For any array of N dimension A(aN-1, ..., a1, a0) + ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as + ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] +; What I will do here is to calculate the following sequence: + ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... + + +#line 1 "mul16.asm" + +__MUL16: ; Mutiplies HL with the last value stored into de stack + ; Works for both signed and unsigned + + PROC + + LOCAL __MUL16LOOP + LOCAL __MUL16NOADD + + ex de, hl + pop hl ; Return address + ex (sp), hl ; CALLEE caller convention + +;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand + ;; ld c, h + ;; ld a, l ; C,A => 1st Operand + ;; + ;; ld hl, 0 ; Accumulator + ;; ld b, 16 + ;; +;;__MUL16LOOP: + ;; sra c ; C,A >> 1 (Arithmetic) + ;; rra + ;; + ;; jr nc, __MUL16NOADD + ;; add hl, de + ;; +;;__MUL16NOADD: + ;; sla e + ;; rl d + ;; + ;; djnz __MUL16LOOP + +__MUL16_FAST: + ld b, 16 + ld a, d + ld c, e + ex de, hl + ld hl, 0 + +__MUL16LOOP: + add hl, hl ; hl << 1 + sla c + rla ; a,c << 1 + jp nc, __MUL16NOADD + add hl, de + +__MUL16NOADD: + djnz __MUL16LOOP + + ret ; Result in hl (16 lower bits) + + ENDP + +#line 20 "array.asm" + +#line 24 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" + +__ARRAY: + PROC + + LOCAL LOOP + LOCAL ARRAY_END + LOCAL RET_ADDRESS ; Stores return address + + ex (sp), hl ; Return address in HL, array address in the stack + ld (RET_ADDRESS + 1), hl ; Stores it for later + + exx + pop hl ; Will use H'L' as the pointer + ld c, (hl) ; Loads Number of dimensions from (hl) + inc hl + ld b, (hl) + inc hl ; Ready + exx + + ld hl, 0 ; BC = Offset "accumulator" + +#line 48 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" + +LOOP: + pop bc ; Get next index (Ai) from the stack + +#line 60 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" + + add hl, bc ; Adds current index + + exx ; Checks if B'C' = 0 + ld a, b ; Which means we must exit (last element is not multiplied by anything) + or c + jr z, ARRAY_END ; if B'Ci == 0 we are done + + ld e, (hl) ; Loads next dimension into D'E' + inc hl + ld d, (hl) + inc hl + push de + dec bc ; Decrements loop counter + exx + pop de ; DE = Max bound Number (i-th dimension) + +#line 80 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" + ;call __MUL16_FAST ; HL *= DE + call __FNMUL +#line 86 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" + jp LOOP + +ARRAY_END: + ld e, (hl) + inc hl + ld d, c ; C = 0 => DE = E = Element size + push hl + push de + exx + +#line 100 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" + LOCAL ARRAY_SIZE_LOOP + + ex de, hl + ld hl, 0 + pop bc + ld b, c +ARRAY_SIZE_LOOP: + add hl, de + djnz ARRAY_SIZE_LOOP + + ;; Even faster + ;pop bc + + ;ld d, h + ;ld e, l + + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, hl + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, hl + ;dec c + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, de + ;__ARRAY_FIN: +#line 131 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" + + pop de + add hl, de ; Adds element start + +RET_ADDRESS: + ld de, 0 + push de + ret ; HL = (Start of Elements + Offset) + + ;; Performs a faster multiply for little 16bit numbs + LOCAL __FNMUL, __FNMUL2 + +__FNMUL: + xor a + or d + jp nz, __MUL16_FAST + + or e + ex de, hl + ret z + + cp 33 + jp nc, __MUL16_FAST + + ld b, l + ld l, h ; HL = 0 + +__FNMUL2: + add hl, de + djnz __FNMUL2 + ret + + ENDP + +#line 26 "array12.bas" +#line 1 "storestr.asm" + +; vim:ts=4:et:sw=4 + ; Stores value of current string pointed by DE register into address pointed by HL + ; Returns DE = Address pointer (&a$) + ; Returns HL = HL (b$ => might be needed later to free it from the heap) + ; + ; e.g. => HL = _variableName (DIM _variableName$) + ; DE = Address into the HEAP + ; + ; This function will resize (REALLOC) the space pointed by HL + ; before copying the content of b$ into a$ + + +#line 1 "strcpy.asm" + +#line 1 "realloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 70 "realloc.asm" +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 70 "alloc.asm" + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/Users/boriel/src/zxbasic/zxbasic/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/Users/boriel/src/zxbasic/zxbasic/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 71 "realloc.asm" +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 72 "realloc.asm" + + + ; --------------------------------------------------------------------- + ; MEM_REALLOC + ; Reallocates a block of memory in the heap. + ; + ; Parameters + ; HL = Pointer to the original block + ; BC = New Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; +; Notes: + ; If BC = 0, the block is freed, otherwise + ; the content of the original block is copied to the new one, and + ; the new size is adjusted. If BC < original length, the content + ; will be truncated. Otherwise, extra block content might contain + ; memory garbage. + ; + ; --------------------------------------------------------------------- +__REALLOC: ; Reallocates block pointed by HL, with new length BC + PROC + + LOCAL __REALLOC_END + + ld a, h + or l + jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc + + ld e, (hl) + inc hl + ld d, (hl) ; DE = First 2 bytes of HL block + + push hl + exx + pop de + inc de ; DE' <- HL + 2 + exx ; DE' <- HL (Saves current pointer into DE') + + dec hl ; HL = Block start + + push de + push bc + call __MEM_FREE ; Frees current block + pop bc + push bc + call __MEM_ALLOC ; Gets a new block of length BC + pop bc + pop de + + ld a, h + or l + ret z ; Return if HL == NULL (No memory) + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Recovers first 2 bytes in HL + + dec bc + dec bc ; BC = BC - 2 (Two bytes copied) + + ld a, b + or c + jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) + + exx + push de + exx + pop de ; DE <- DE' ; Start of remaining block + + push hl ; Saves current Block + 2 start + ex de, hl ; Exchanges them: DE is destiny block + ldir ; Copies BC Bytes + pop hl ; Recovers Block + 2 start + +__REALLOC_END: + + dec hl ; Set HL + dec hl ; To begin of block + ret + + ENDP + +#line 2 "strcpy.asm" + + ; String library + + +__STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) + PROC + + LOCAL __STRREALLOC + LOCAL __STRCONTINUE + LOCAL __B_IS_NULL + LOCAL __NOTHING_TO_COPY + + ld b, d + ld c, e + ld a, b + or c + jr z, __B_IS_NULL + + ex de, hl + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(b$) + ex de, hl ; DE = &b$ + +__B_IS_NULL: ; Jumps here if B$ pointer is NULL + inc bc + inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) + + push de + push hl + + ld a, h + or l + jr z, __STRREALLOC + + dec hl + ld d, (hl) + dec hl + ld e, (hl) ; DE = MEMBLOCKSIZE(a$) + dec de + dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) + + ld h, b + ld l, c ; HL = LEN(b$) + 2 => Minimum block size required + ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 + + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) + sbc hl, de ; Carry if len(b$) > Blocklen(a$) + jr c, __STRREALLOC ; No need to realloc + ; Need to reallocate at least to len(b$) + 2 + ex de, hl ; DE = Remaining bytes in a$ mem block. + ld hl, 4 + sbc hl, de ; if remaining bytes < 4 we can continue + jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes + +__STRREALLOC: + pop hl + call __REALLOC ; Returns in HL a new pointer with BC bytes allocated + push hl + +__STRCONTINUE: ; Pops hl and de SWAPPED + pop de ; DE = &a$ + pop hl ; HL = &b$ + + ld a, d ; Return if not enough memory for new length + or e + ret z ; Return if DE == NULL (0) + +__STRCPY: ; Copies string pointed by HL into string pointed by DE + ; Returns DE as HL (new pointer) + ld a, h + or l + jr z, __NOTHING_TO_COPY + ld c, (hl) + inc hl + ld b, (hl) + dec hl + inc bc + inc bc + push de + ldir + pop hl + ret + +__NOTHING_TO_COPY: + ex de, hl + ld (hl), e + inc hl + ld (hl), d + dec hl + ret + + ENDP + +#line 14 "storestr.asm" + +__PISTORE_STR: ; Indirect assignement at (IX + BC) + push ix + pop hl + add hl, bc + +__ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + +__STORE_STR: + push de ; Pointer to b$ + push hl ; Array pointer to variable memory address + + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation + ex de, hl ; DE = new address of a$ + pop hl ; Recover variable memory address pointer + + ld (hl), e + inc hl + ld (hl), d ; Stores a$ ptr into elemem ptr + + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) + ret + +#line 27 "array12.bas" + +ZXBASIC_USER_DATA: +_b: + DEFB 00, 00 +_s: + DEFB 00, 00 +_a: + DEFW 0001h + DEFW 000Bh + DEFB 02h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/array12.bas b/tests/functional/array12.bas new file mode 100644 index 000000000..6b5d7594d --- /dev/null +++ b/tests/functional/array12.bas @@ -0,0 +1,6 @@ +DIM a$(10, 10) +DIM b as Uinteger +DIM s as String + +a$(b, b) = s + diff --git a/tests/functional/lcd6.asm b/tests/functional/lcd6.asm new file mode 100644 index 000000000..f09d9c109 --- /dev/null +++ b/tests/functional/lcd6.asm @@ -0,0 +1,109 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +_SubLifetime: + push ix + ld ix, 0 + add ix, sp + ld hl, -21 + add hl, sp + ld sp, hl + ld (hl), 0 + ld bc, 20 + ld d, h + ld e, l + inc de + ldir + push ix + pop hl + ld bc, -21 + add hl, bc + ex de, hl + ld hl, __LABEL0 + ld bc, 3 + ldir +_SubLifetime__leave: + ld sp, ix + pop ix + exx + pop hl + pop bc + pop bc + ex (sp), hl + exx + ret + +ZXBASIC_USER_DATA: +_tile: + DEFW 0000h + DEFB 02h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h +__LABEL0: + DEFB 00h + DEFB 00h + DEFB 01h + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/lcd6.bas b/tests/functional/lcd6.bas new file mode 100644 index 000000000..177f68553 --- /dev/null +++ b/tests/functional/lcd6.bas @@ -0,0 +1,5 @@ +dim tile(17) as Uinteger +sub SubLifetime(x as integer,y as integer,value as byte) + dim tile(17) as ubyte +end sub + diff --git a/tests/functional/ltee10.asm b/tests/functional/ltee10.asm new file mode 100644 index 000000000..c607a54c9 --- /dev/null +++ b/tests/functional/ltee10.asm @@ -0,0 +1,277 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +_setlocal: + push ix + ld ix, 0 + add ix, sp + ld hl, 0 + push hl + push hl + push hl + push ix + pop hl + ld bc, -6 + add hl, bc + ex de, hl + ld hl, __LABEL0 + ld bc, 6 + ldir + ld a, (_pos) + ld l, a + ld h, 0 + push hl + push ix + pop hl + ld de, -6 + add hl, de + call __ARRAY + ld (hl), 3 +_setlocal__leave: + ld sp, ix + pop ix + ret +#line 1 "array.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; ------------------------------------------------------------------- + ; Simple array Index routine + ; Number of total indexes dimensions - 1 at beginning of memory + ; HL = Start of array memory (First two bytes contains N-1 dimensions) + ; Dimension values on the stack, (top of the stack, highest dimension) + ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> + + ; For any array of N dimension A(aN-1, ..., a1, a0) + ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as + ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] +; What I will do here is to calculate the following sequence: + ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... + + +#line 1 "mul16.asm" + +__MUL16: ; Mutiplies HL with the last value stored into de stack + ; Works for both signed and unsigned + + PROC + + LOCAL __MUL16LOOP + LOCAL __MUL16NOADD + + ex de, hl + pop hl ; Return address + ex (sp), hl ; CALLEE caller convention + +;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand + ;; ld c, h + ;; ld a, l ; C,A => 1st Operand + ;; + ;; ld hl, 0 ; Accumulator + ;; ld b, 16 + ;; +;;__MUL16LOOP: + ;; sra c ; C,A >> 1 (Arithmetic) + ;; rra + ;; + ;; jr nc, __MUL16NOADD + ;; add hl, de + ;; +;;__MUL16NOADD: + ;; sla e + ;; rl d + ;; + ;; djnz __MUL16LOOP + +__MUL16_FAST: + ld b, 16 + ld a, d + ld c, e + ex de, hl + ld hl, 0 + +__MUL16LOOP: + add hl, hl ; hl << 1 + sla c + rla ; a,c << 1 + jp nc, __MUL16NOADD + add hl, de + +__MUL16NOADD: + djnz __MUL16LOOP + + ret ; Result in hl (16 lower bits) + + ENDP + +#line 20 "array.asm" + +#line 24 "/src/zxb/trunk/library-asm/array.asm" + +__ARRAY: + PROC + + LOCAL LOOP + LOCAL ARRAY_END + LOCAL RET_ADDRESS ; Stores return address + + ex (sp), hl ; Return address in HL, array address in the stack + ld (RET_ADDRESS + 1), hl ; Stores it for later + + exx + pop hl ; Will use H'L' as the pointer + ld c, (hl) ; Loads Number of dimensions from (hl) + inc hl + ld b, (hl) + inc hl ; Ready + exx + + ld hl, 0 ; BC = Offset "accumulator" + +#line 48 "/src/zxb/trunk/library-asm/array.asm" + +LOOP: + pop bc ; Get next index (Ai) from the stack + +#line 60 "/src/zxb/trunk/library-asm/array.asm" + + add hl, bc ; Adds current index + + exx ; Checks if B'C' = 0 + ld a, b ; Which means we must exit (last element is not multiplied by anything) + or c + jr z, ARRAY_END ; if B'Ci == 0 we are done + + ld e, (hl) ; Loads next dimension into D'E' + inc hl + ld d, (hl) + inc hl + push de + dec bc ; Decrements loop counter + exx + pop de ; DE = Max bound Number (i-th dimension) + +#line 80 "/src/zxb/trunk/library-asm/array.asm" + ;call __MUL16_FAST ; HL *= DE + call __FNMUL +#line 86 "/src/zxb/trunk/library-asm/array.asm" + jp LOOP + +ARRAY_END: + ld e, (hl) + inc hl + ld d, c ; C = 0 => DE = E = Element size + push hl + push de + exx + +#line 100 "/src/zxb/trunk/library-asm/array.asm" + LOCAL ARRAY_SIZE_LOOP + + ex de, hl + ld hl, 0 + pop bc + ld b, c +ARRAY_SIZE_LOOP: + add hl, de + djnz ARRAY_SIZE_LOOP + + ;; Even faster + ;pop bc + + ;ld d, h + ;ld e, l + + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, hl + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, hl + ;dec c + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, de + ;__ARRAY_FIN: +#line 131 "/src/zxb/trunk/library-asm/array.asm" + + pop de + add hl, de ; Adds element start + +RET_ADDRESS: + ld de, 0 + push de + ret ; HL = (Start of Elements + Offset) + + ;; Performs a faster multiply for little 16bit numbs + LOCAL __FNMUL, __FNMUL2 + +__FNMUL: + xor a + or d + jp nz, __MUL16_FAST + + or e + ex de, hl + ret z + + cp 33 + jp nc, __MUL16_FAST + + ld b, l + ld l, h ; HL = 0 + +__FNMUL2: + add hl, de + djnz __FNMUL2 + ret + + ENDP + +#line 48 "ltee10.bas" + +ZXBASIC_USER_DATA: +_pos: + DEFB 00 +__LABEL0: + DEFB 00h + DEFB 00h + DEFB 01h + DEFB 00h + DEFB 01h + DEFB 02h + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ltee10.bas b/tests/functional/ltee10.bas new file mode 100644 index 000000000..fb3949b01 --- /dev/null +++ b/tests/functional/ltee10.bas @@ -0,0 +1,7 @@ +dim pos as UBYTE + +sub setlocal + dim testglobal(2) as Byte => {0, 1, 2} + testglobal(pos) = 3 +end sub + diff --git a/tests/functional/subparam.asm b/tests/functional/subparam.asm new file mode 100644 index 000000000..e743019ca --- /dev/null +++ b/tests/functional/subparam.asm @@ -0,0 +1,55 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld a, 87 + push af + ld a, 127 + push af + call _test + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +_test: + push ix + ld ix, 0 + add ix, sp + ld a, (ix+7) + ld (ix+5), a +_test__leave: + ld sp, ix + pop ix + exx + pop hl + pop bc + ex (sp), hl + exx + ret + +ZXBASIC_USER_DATA: + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/subparam.bas b/tests/functional/subparam.bas new file mode 100644 index 000000000..73bebc947 --- /dev/null +++ b/tests/functional/subparam.bas @@ -0,0 +1,9 @@ + + +SUB test(x as UByte, y as Ubyte) + Let x = y +END SUB + +REM calls a sub with no parameters +test 127, 87 + diff --git a/zxblex.py b/zxblex.py index 534acfd54..410a548a8 100755 --- a/zxblex.py +++ b/zxblex.py @@ -12,6 +12,7 @@ import sys from ply import lex from keywords import KEYWORDS as reserved +import api from api.errmsg import syntax_error @@ -31,6 +32,7 @@ # List of token names. _tokens = ( + 'ARRAY_ID', # This ID is a variable name from an array 'NUMBER', 'PLUS', 'MINUS', 'MUL', 'DIV', 'POW', 'LP', 'RP', 'LT', 'LBRACE', 'RBRACE', 'EQ', 'GT', 'LE', 'GE', 'NE', 'ID', @@ -497,6 +499,10 @@ def t_ID(t): if t.type != 'ID': t.value = t.type + else: + entry = api.global_.SYMBOL_TABLE.get_entry(t.value) + if entry and entry.class_ == api.constants.CLASS.array: + t.type = 'ARRAY_ID' if t.type == 'BIN': t.lexer.begin('bin') diff --git a/zxbparser.py b/zxbparser.py index 331feb696..7ee1f4b62 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -580,29 +580,39 @@ def p_var_decl_ini(p): def p_idlist_id(p): """ idlist : ID + | ARRAY_ID """ p[0] = [(p[1], p.lineno(1))] def p_idlist_idlist_id(p): """ idlist : idlist COMMA ID + | idlist COMMA ARRAY_ID """ p[0] = p[1] + [(p[3], p.lineno(3))] def p_arr_decl(p): - """ var_decl : DIM ID LP bound_list RP typedef NEWLINE - | DIM ID LP bound_list RP typedef CO + """ var_decl : var_arr_decl NEWLINE + | var_arr_decl CO """ - SYMBOL_TABLE.declare_array(p[2], p.lineno(2), p[6], p[4]) p[0] = None +def p_decl_arr(p): + """ var_arr_decl : DIM idlist LP bound_list RP typedef + """ + if len(p[2]) != 1: + syntax_error(p.lineno(1), "Array declaration only allows one variable name at a time") + else: + id_, lineno = p[2][0] + SYMBOL_TABLE.declare_array(id_, lineno, p[6], p[4]) + p[0] = p[2][0] + + def p_arr_decl_initialized(p): - """ var_decl : DIM ID LP bound_list RP typedef RIGHTARROW const_vector NEWLINE - | DIM ID LP bound_list RP typedef RIGHTARROW const_vector CO - | DIM ID LP bound_list RP typedef EQ const_vector NEWLINE - | DIM ID LP bound_list RP typedef EQ const_vector CO + """ var_arr_decl : DIM idlist LP bound_list RP typedef RIGHTARROW const_vector + | DIM idlist LP bound_list RP typedef EQ const_vector """ def check_bound(boundlist, remaining): @@ -634,7 +644,8 @@ def check_bound(boundlist, remaining): return if check_bound(p[4].children, p[8]): - SYMBOL_TABLE.declare_array(p[2], p.lineno(2), p[6], p[4], default_value=p[8]) + id_, lineno = p[2][0] + SYMBOL_TABLE.declare_array(id_, lineno, p[6], p[4], default_value=p[8]) p[0] = None @@ -866,6 +877,8 @@ def p_statement_beep(p): def p_statement_call(p): """ statement : ID arg_list NEWLINE | ID arg_list CO + | ID arguments NEWLINE + | ID arguments CO | ID NEWLINE | ID CO """ @@ -944,6 +957,8 @@ def p_assignment(p): def p_lexpr(p): """ lexpr : ID EQ | LET ID EQ + | ARRAY_ID EQ + | LET ARRAY_ID EQ """ global LET_ASSIGNMENT @@ -960,6 +975,35 @@ def p_lexpr(p): def p_arr_assignment(p): + """ statement : ARRAY_ID arg_list EQ expr CO + | ARRAY_ID arg_list EQ expr NEWLINE + | LET ARRAY_ID arg_list EQ expr CO + | LET ARRAY_ID arg_list EQ expr NEWLINE + """ + q = p[1:] + i = 2 + if q[0].upper() == 'LET': + q = q[1:] + i = 3 + + if q[1] is None or q[3] is None: + return # There where errors + + p[0] = None + # api.check.check_is_declared_strict(p.lineno(i - 1), q[0], classname='array') + + entry = SYMBOL_TABLE.access_call(q[0], p.lineno(i - 1)) + if entry is None: + # variable = SYMBOL_TABLE.make_var(q[0], p.lineno(1), TYPE.string) + # entry = SYMBOL_TABLE.get_id_entry(q[0]) + return + + arr = make_array_access(q[0], p.lineno(i), q[1]) + expr = make_typecast(arr.type_, q[3], p.lineno(i)) + p[0] = make_sentence('LETARRAY', arr, expr) + + +def p_substr_assignment(p): """ statement : ID arg_list EQ expr CO | ID arg_list EQ expr NEWLINE | LET ID arg_list EQ expr CO @@ -983,40 +1027,35 @@ def p_arr_assignment(p): # entry = SYMBOL_TABLE.get_id_entry(q[0]) return - if entry.class_ == CLASS.var and entry.type_ == TYPE.string: - r = q[3] - if r.type_ != TYPE.string: - api.errmsg.syntax_error_expected_string(p.lineno(i - 1), r.type_) - - if len(q[1]) > 1: - syntax_error(p.lineno(i), "Too many values. Expected only one.") - return + assert entry.class_ == CLASS.var and entry.type_ == TYPE.string + r = q[3] + if r.type_ != TYPE.string: + api.errmsg.syntax_error_expected_string(p.lineno(i - 1), r.type_) - if len(q[1]) == 1: - substr = ( - make_typecast(_TYPE(gl.STR_INDEX_TYPE), q[1][0].value, p.lineno(i)), - make_typecast(_TYPE(gl.STR_INDEX_TYPE), q[1][0].value, p.lineno(i))) - else: - substr = (make_typecast(_TYPE(gl.STR_INDEX_TYPE), - make_number(gl.MIN_STRSLICE_IDX, - lineno=p.lineno(i)), - p.lineno(i)), - make_typecast(_TYPE(gl.STR_INDEX_TYPE), - make_number(gl.MAX_STRSLICE_IDX, - lineno=p.lineno(i)), - p.lineno(i))) - - lineno = p.lineno(0) - base = make_number(OPTIONS.string_base.value, lineno, _TYPE(gl.STR_INDEX_TYPE)) - p[0] = make_sentence('LETSUBSTR', entry, - make_binary(lineno, 'MINUS', substr[0], base, func=lambda x, y: x - y), - make_binary(lineno, 'MINUS', substr[1], base, func=lambda x, y: x - y), - r) + if len(q[1]) > 1: + syntax_error(p.lineno(i), "Too many values. Expected only one.") return - arr = make_array_access(q[0], p.lineno(i), q[1]) - expr = make_typecast(arr.type_, q[3], p.lineno(i)) - p[0] = make_sentence('LETARRAY', arr, expr) + if len(q[1]) == 1: + substr = ( + make_typecast(_TYPE(gl.STR_INDEX_TYPE), q[1][0].value, p.lineno(i)), + make_typecast(_TYPE(gl.STR_INDEX_TYPE), q[1][0].value, p.lineno(i))) + else: + substr = (make_typecast(_TYPE(gl.STR_INDEX_TYPE), + make_number(gl.MIN_STRSLICE_IDX, + lineno=p.lineno(i)), + p.lineno(i)), + make_typecast(_TYPE(gl.STR_INDEX_TYPE), + make_number(gl.MAX_STRSLICE_IDX, + lineno=p.lineno(i)), + p.lineno(i))) + + lineno = p.lineno(0) + base = make_number(OPTIONS.string_base.value, lineno, _TYPE(gl.STR_INDEX_TYPE)) + p[0] = make_sentence('LETSUBSTR', entry, + make_binary(lineno, 'MINUS', substr[0], base, func=lambda x, y: x - y), + make_binary(lineno, 'MINUS', substr[1], base, func=lambda x, y: x - y), + r) def p_str_assign(p): @@ -2374,6 +2413,7 @@ def p_exprstr_file(p): def p_id_expr(p): """ expr : ID + | ARRAY_ID """ entry = SYMBOL_TABLE.access_id(p[1], p.lineno(1), default_class=CLASS.var) if entry is None: @@ -2406,6 +2446,7 @@ def p_id_expr(p): def p_addr_of_id(p): """ expr : ADDRESSOF ID + | ADDRESSOF ARRAY_ID """ entry = SYMBOL_TABLE.access_id(p[2], p.lineno(2)) if entry is None: @@ -2429,7 +2470,7 @@ def p_expr_funccall(p): def p_idcall_expr(p): """ func_call : ID arg_list - """ # This can be a function call, an array call or a string index + """ # This can be a function call or a string index p[0] = make_call(p[1], p.lineno(1), p[2]) if p[0] is None: return @@ -2446,8 +2487,19 @@ def p_idcall_expr(p): p[0].entry.accessed = True -def p_addr_of_func_call(p): - """ expr : ADDRESSOF ID arg_list +def p_arr_access_expr(p): + """ func_call : ARRAY_ID arg_list + """ # This is an array access + p[0] = make_call(p[1], p.lineno(1), p[2]) + if p[0] is None: + return + + entry = SYMBOL_TABLE.access_call(p[1], p.lineno(1)) + entry.accessed = True + + +def p_addr_of_array_element(p): + """ expr : ADDRESSOF ARRAY_ID arg_list """ p[0] = None @@ -2462,6 +2514,13 @@ def p_addr_of_func_call(p): p[0] = make_unary(p.lineno(1), 'ADDRESS', result, type_=_TYPE(gl.PTR_TYPE)) +def p_err_undefined_arr_access(p): + """ expr : ADDRESSOF ID arg_list + """ + syntax_error(p.lineno(2), 'Undeclared array "%s"' % p[2]) + p[0] = None + + def p_arg_list(p): """ arg_list : LP RP """ @@ -2832,8 +2891,8 @@ def p_expr_in(p): def p_expr_lbound(p): - """ expr : LBOUND LP ID RP - | UBOUND LP ID RP + """ expr : LBOUND LP ARRAY_ID RP + | UBOUND LP ARRAY_ID RP """ entry = SYMBOL_TABLE.access_array(p[3], p.lineno(3)) if entry is None: @@ -2851,8 +2910,8 @@ def p_expr_lbound(p): def p_expr_lbound_expr(p): - """ expr : LBOUND LP ID COMMA expr RP - | UBOUND LP ID COMMA expr RP + """ expr : LBOUND LP ARRAY_ID COMMA expr RP + | UBOUND LP ARRAY_ID COMMA expr RP """ entry = SYMBOL_TABLE.access_array(p[3], p.lineno(3)) if entry is None: @@ -2907,6 +2966,7 @@ def p_len(p): def p_sizeof(p): """ expr : SIZEOF LP type RP | SIZEOF LP ID RP + | SIZEOF LP ARRAY_ID RP """ if TYPE.to_type(p[3].lower()) is not None: p[0] = make_number(TYPE.size(TYPE.to_type(p[3].lower())), From c435c82ecbe4d02ef92c163ca44aa033a8383769 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 20 Sep 2017 21:34:06 +0200 Subject: [PATCH 063/247] tie-in for SUBs and FUNCTions --- zxblex.py | 11 ++++- zxbparser.py | 114 ++++++++++++++++++++++++++++++++------------------- 2 files changed, 80 insertions(+), 45 deletions(-) diff --git a/zxblex.py b/zxblex.py index 410a548a8..10fea2dbe 100755 --- a/zxblex.py +++ b/zxblex.py @@ -33,6 +33,8 @@ # List of token names. _tokens = ( 'ARRAY_ID', # This ID is a variable name from an array + 'FUNC_ID', # This ID is a function name, + 'SUB_ID', # This ID is a sub name 'NUMBER', 'PLUS', 'MINUS', 'MUL', 'DIV', 'POW', 'LP', 'RP', 'LT', 'LBRACE', 'RBRACE', 'EQ', 'GT', 'LE', 'GE', 'NE', 'ID', @@ -496,13 +498,18 @@ def t_preproc_EQ(t): def t_ID(t): r'[a-zA-Z][a-zA-Z0-9]*[$%]?' t.type = reserved.get(t.value.lower(), 'ID') + callables = { + api.constants.CLASS.array: 'ARRAY_ID', + api.constants.CLASS.function: 'FUNC_ID', + api.constants.CLASS.sub: 'SUB_ID' + } if t.type != 'ID': t.value = t.type else: entry = api.global_.SYMBOL_TABLE.get_entry(t.value) - if entry and entry.class_ == api.constants.CLASS.array: - t.type = 'ARRAY_ID' + if entry: + t.type = callables.get(entry.class_, t.type) if t.type == 'BIN': t.lexer.begin('bin') diff --git a/zxbparser.py b/zxbparser.py index 7ee1f4b62..e391cf673 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -581,6 +581,8 @@ def p_var_decl_ini(p): def p_idlist_id(p): """ idlist : ID | ARRAY_ID + | SUB_ID + | FUNC_ID """ p[0] = [(p[1], p.lineno(1))] @@ -959,6 +961,10 @@ def p_lexpr(p): | LET ID EQ | ARRAY_ID EQ | LET ARRAY_ID EQ + | SUB_ID EQ + | LET SUB_ID EQ + | FUNC_ID EQ + | LET FUNC_ID EQ """ global LET_ASSIGNMENT @@ -1974,6 +1980,13 @@ def p_save_code(p): | SAVE expr CODE expr COMMA expr NEWLINE | SAVE expr ID NEWLINE | SAVE expr ID CO + | SAVE expr ARRAY_ID CO + | SAVE expr ARRAY_ID NEWLINE + | SAVE expr FUNC_ID CO + | SAVE expr FUNC_ID NEWLINE + | SAVE expr SUB_ID CO + | SAVE expr SUB_ID NEWLINE + """ if p[2].type_ != TYPE.string: api.errmsg.syntax_error_expected_string(p.lineno(1), p[2].type_) @@ -2292,25 +2305,25 @@ def p_cast(p): def p_number_expr(p): - """ expr : NUMBER + """ bexpr : NUMBER """ p[0] = make_number(p[1], lineno=p.lineno(1)) def p_expr_PI(p): - """ expr : PI + """ bexpr : PI """ p[0] = make_number(PI, lineno=p.lineno(1), type_=TYPE.float_) def p_number_line(p): - """ expr : __LINE__ + """ bexpr : __LINE__ """ p[0] = make_number(p.lineno(1), lineno=p.lineno(1)) def p_expr_string(p): - """ expr : string + """ bexpr : string """ p[0] = p[1] @@ -2406,13 +2419,13 @@ def p_subind_TO(p): def p_exprstr_file(p): - """ expr : __FILE__ + """ bexpr : __FILE__ """ p[0] = symbols.STRING(gl.FILENAME, p.lineno(1)) def p_id_expr(p): - """ expr : ID + """ bexpr : ID | ARRAY_ID """ entry = SYMBOL_TABLE.access_id(p[1], p.lineno(1), default_class=CLASS.var) @@ -2445,7 +2458,7 @@ def p_id_expr(p): def p_addr_of_id(p): - """ expr : ADDRESSOF ID + """ bexpr : ADDRESSOF ID | ADDRESSOF ARRAY_ID """ entry = SYMBOL_TABLE.access_id(p[2], p.lineno(2)) @@ -2462,24 +2475,25 @@ def p_addr_of_id(p): p[0] = make_constexpr(p.lineno(1), result) +def p_expr_bexpr(p): + """ expr : bexpr + """ + p[0] = p[1] + + def p_expr_funccall(p): - """ expr : func_call + """ bexpr : func_call """ p[0] = p[1] def p_idcall_expr(p): - """ func_call : ID arg_list + """ func_call : FUNC_ID arg_list """ # This can be a function call or a string index p[0] = make_call(p[1], p.lineno(1), p[2]) if p[0] is None: return - if p[0].token in ('STRSLICE', 'VAR', 'STRING'): - entry = SYMBOL_TABLE.access_call(p[1], p.lineno(1)) - entry.accessed = True - return - # TODO: Check that arrays really needs kind=function to be set # Both array accesses and functions are tagged as functions # functions also has the class_ attribute set to 'function' @@ -2499,7 +2513,7 @@ def p_arr_access_expr(p): def p_addr_of_array_element(p): - """ expr : ADDRESSOF ARRAY_ID arg_list + """ bexpr : ADDRESSOF ARRAY_ID arg_list """ p[0] = None @@ -2515,12 +2529,27 @@ def p_addr_of_array_element(p): def p_err_undefined_arr_access(p): - """ expr : ADDRESSOF ID arg_list + """ bexpr : ADDRESSOF ID arg_list """ syntax_error(p.lineno(2), 'Undeclared array "%s"' % p[2]) p[0] = None +def p_bexpr_func(p): + """ bexpr : FUNC_ID bexpr + """ + args = make_arg_list(make_argument(p[1], p.lineno(0))) + p[0] = make_call(p[1], p.lineno(1), args) + if p[0] is None: + return + + # TODO: Check that arrays really needs kind=function to be set + # Both array accesses and functions are tagged as functions + # functions also has the class_ attribute set to 'function' + p[0].entry.set_kind(KIND.function, p.lineno(1)) + p[0].entry.accessed = True + + def p_arg_list(p): """ arg_list : LP RP """ @@ -2849,7 +2878,7 @@ def p_preproc_line_pop(p): # ---------------------------------------- def p_expr_usr(p): - """ expr : USR expr %prec UMINUS + """ bexpr : USR bexpr %prec UMINUS """ if p[2].type_ == TYPE.string: p[0] = make_builtin(p.lineno(1), 'USR_STR', p[2], type_=TYPE.uinteger) @@ -2860,14 +2889,14 @@ def p_expr_usr(p): def p_expr_rnd(p): - """ expr : RND + """ bexpr : RND | RND LP RP """ p[0] = make_builtin(p.lineno(1), 'RND', None, type_=TYPE.float_) def p_expr_peek(p): - """ expr : PEEK expr %prec UMINUS + """ bexpr : PEEK bexpr %prec UMINUS """ p[0] = make_builtin(p.lineno(1), 'PEEK', make_typecast(TYPE.uinteger, p[2], p.lineno(1)), @@ -2875,7 +2904,7 @@ def p_expr_peek(p): def p_expr_peektype_(p): - """ expr : PEEK LP numbertype COMMA expr RP + """ bexpr : PEEK LP numbertype COMMA expr RP """ p[0] = make_builtin(p.lineno(1), 'PEEK', make_typecast(TYPE.uinteger, p[5], p.lineno(4)), @@ -2883,7 +2912,7 @@ def p_expr_peektype_(p): def p_expr_in(p): - """ expr : IN expr %prec UMINUS + """ bexpr : IN bexpr %prec UMINUS """ p[0] = make_builtin(p.lineno(1), 'IN', make_typecast(TYPE.uinteger, p[2], p.lineno(1)), @@ -2891,7 +2920,7 @@ def p_expr_in(p): def p_expr_lbound(p): - """ expr : LBOUND LP ARRAY_ID RP + """ bexpr : LBOUND LP ARRAY_ID RP | UBOUND LP ARRAY_ID RP """ entry = SYMBOL_TABLE.access_array(p[3], p.lineno(3)) @@ -2947,7 +2976,7 @@ def p_expr_lbound_expr(p): def p_len(p): - """ expr : LEN expr %prec UMINUS + """ bexpr : LEN bexpr %prec UMINUS """ arg = p[2] if arg is None: @@ -2964,7 +2993,7 @@ def p_len(p): def p_sizeof(p): - """ expr : SIZEOF LP type RP + """ bexpr : SIZEOF LP type RP | SIZEOF LP ID RP | SIZEOF LP ARRAY_ID RP """ @@ -2994,7 +3023,7 @@ def p_inkey(p): def p_chr_one(p): - """ string : CHR expr %prec UMINUS + """ string : CHR bexpr %prec UMINUS """ arg_list = make_arg_list(make_argument(p[2], p.lineno(1))) arg_list[0].value = make_typecast(TYPE.ubyte, arg_list[0].value, p.lineno(1)) @@ -3016,7 +3045,7 @@ def p_chr(p): def p_val(p): - """ expr : VAL expr %prec UMINUS + """ bexpr : VAL bexpr %prec UMINUS """ def val(s): @@ -3035,7 +3064,7 @@ def val(s): def p_code(p): - """ expr : CODE expr %prec UMINUS + """ bexpr : CODE bexpr %prec UMINUS """ def asc(x): @@ -3056,7 +3085,7 @@ def asc(x): def p_sgn(p): - """ expr : SGN expr %prec UMINUS + """ bexpr : SGN bexpr %prec UMINUS """ sgn = lambda x: x < 0 and -1 or x > 0 and 1 or 0 # noqa @@ -3069,12 +3098,12 @@ def p_sgn(p): p[0] = make_builtin(p.lineno(1), 'SGN', p[2], lambda x: sgn(x), type_=TYPE.byte_) - +''' # ---------------------------------------- # Trigonometrics # ---------------------------------------- def p_expr_sin(p): - """ expr : SIN expr %prec UMINUS + """ bexpr : SIN bexpr %prec UMINUS """ p[0] = make_builtin(p.lineno(1), 'SIN', make_typecast(TYPE.float_, p[2], p.lineno(1)), @@ -3082,7 +3111,7 @@ def p_expr_sin(p): def p_expr_cos(p): - """ expr : COS expr %prec UMINUS + """ bexpr : COS bexpr %prec UMINUS """ p[0] = make_builtin(p.lineno(1), 'COS', make_typecast(TYPE.float_, p[2], p.lineno(1)), @@ -3090,7 +3119,7 @@ def p_expr_cos(p): def p_expr_tan(p): - """ expr : TAN expr %prec UMINUS + """ bexpr : TAN bexpr %prec UMINUS """ p[0] = make_builtin(p.lineno(1), 'TAN', make_typecast(TYPE.float_, p[2], p.lineno(1)), @@ -3098,7 +3127,7 @@ def p_expr_tan(p): def p_expr_asin(p): - """ expr : ASN expr %prec UMINUS + """ bexpr : ASN bexpr %prec UMINUS """ p[0] = make_builtin(p.lineno(1), 'ASN', make_typecast(TYPE.float_, p[2], p.lineno(1)), @@ -3106,7 +3135,7 @@ def p_expr_asin(p): def p_expr_acos(p): - """ expr : ACS expr %prec UMINUS + """ bexpr : ACS bexpr %prec UMINUS """ p[0] = make_builtin(p.lineno(1), 'ACS', make_typecast(TYPE.float_, p[2], p.lineno(1)), @@ -3114,7 +3143,7 @@ def p_expr_acos(p): def p_expr_atan(p): - """ expr : ATN expr %prec UMINUS + """ bexpr : ATN bexpr %prec UMINUS """ p[0] = make_builtin(p.lineno(1), 'ATN', make_typecast(TYPE.float_, p[2], p.lineno(1)), @@ -3125,7 +3154,7 @@ def p_expr_atan(p): # Square root, Exponent and logarithms # ---------------------------------------- def p_expr_exp(p): - """ expr : EXP expr %prec UMINUS + """ bexpr : EXP bexpr %prec UMINUS """ p[0] = make_builtin(p.lineno(1), 'EXP', make_typecast(TYPE.float_, p[2], p.lineno(1)), @@ -3133,7 +3162,7 @@ def p_expr_exp(p): def p_expr_logn(p): - """ expr : LN expr %prec UMINUS + """ bexpr : LN bexpr %prec UMINUS """ p[0] = make_builtin(p.lineno(1), 'LN', make_typecast(TYPE.float_, p[2], p.lineno(1)), @@ -3141,7 +3170,7 @@ def p_expr_logn(p): def p_expr_sqrt(p): - """ expr : SQR expr %prec UMINUS + """ bexpr : SQR bexpr %prec UMINUS """ p[0] = make_builtin(p.lineno(1), 'SQR', make_typecast(TYPE.float_, p[2], p.lineno(1)), @@ -3152,13 +3181,13 @@ def p_expr_sqrt(p): # Other important functions # ---------------------------------------- def p_expr_int(p): - """ expr : INT expr %prec UMINUS + """ bexpr : INT bexpr %prec UMINUS """ p[0] = make_typecast(TYPE.long_, p[2], p.lineno(1)) def p_abs(p): - """ expr : ABS expr %prec UMINUS + """ bexpr : ABS bexpr %prec UMINUS """ if is_unsigned(p[2]): p[0] = p[2] @@ -3166,8 +3195,7 @@ def p_abs(p): return p[0] = make_builtin(p.lineno(1), 'ABS', p[2], lambda x: x if x >= 0 else -x) - - +''' # ---------------------------------------- # The yyerror function # ---------------------------------------- @@ -3191,7 +3219,7 @@ def p_error(p): # ---------------------------------------- # Initialization # ---------------------------------------- -parser = yacc.yacc(method='LALR', tabmodule='parsetab.zxbtab', debug=OPTIONS.Debug.value > 2) +parser = yacc.yacc(method='LALR', tabmodule='parsetab.zxbtab') #, debug=OPTIONS.Debug.value > 2) ast = None data_ast = None # Global Variables AST optemps = OpcodesTemps() From 67778432a19d048ba812ae58b5735dbe46c6d0e4 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 22 Sep 2017 22:42:31 +0200 Subject: [PATCH 064/247] emit an ERROR token on invalid character Instead of supressing the character emit an invalid token. --- zxblex.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/zxblex.py b/zxblex.py index 10fea2dbe..56ea426ad 100755 --- a/zxblex.py +++ b/zxblex.py @@ -33,8 +33,6 @@ # List of token names. _tokens = ( 'ARRAY_ID', # This ID is a variable name from an array - 'FUNC_ID', # This ID is a function name, - 'SUB_ID', # This ID is a sub name 'NUMBER', 'PLUS', 'MINUS', 'MUL', 'DIV', 'POW', 'LP', 'RP', 'LT', 'LBRACE', 'RBRACE', 'EQ', 'GT', 'LE', 'GE', 'NE', 'ID', @@ -500,8 +498,6 @@ def t_ID(t): t.type = reserved.get(t.value.lower(), 'ID') callables = { api.constants.CLASS.array: 'ARRAY_ID', - api.constants.CLASS.function: 'FUNC_ID', - api.constants.CLASS.sub: 'SUB_ID' } if t.type != 'ID': @@ -604,10 +600,10 @@ def t_INITIAL_bin_preproc_SEPARATOR(t): pass -def t_INITIAL_bin_string_asm_preproc_comment_ANYCHAR(t): +def t_INITIAL_bin_string_asm_preproc_comment_ERROR(t): r'.' syntax_error(t.lineno, "ignoring illegal character '%s'" % t.value[0]) - pass + return t # error handling rule From 3ec57add880998a2a54b167c9471d4df0bd1bbec Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 20 Sep 2017 00:38:10 +0200 Subject: [PATCH 065/247] allow calling funct with no parenthesis if 1 param Functions with only one or no parameters can now be called without them, like internal functions. Eg. SIN x or MyFUNC 5 --- tests/functional/70.asm | 422 +++++++++++++++++++++++++++++++ tests/functional/70.bas | 5 + tests/functional/funcnoparm.asm | 60 +++++ tests/functional/funcnoparm.bas | 8 + tests/functional/funcnoparm2.bas | 9 + tests/functional/test_.py | 3 +- zxbparser.py | 123 +++------ 7 files changed, 543 insertions(+), 87 deletions(-) create mode 100644 tests/functional/70.asm create mode 100644 tests/functional/70.bas create mode 100644 tests/functional/funcnoparm.asm create mode 100644 tests/functional/funcnoparm.bas create mode 100644 tests/functional/funcnoparm2.bas diff --git a/tests/functional/70.asm b/tests/functional/70.asm new file mode 100644 index 000000000..7c8685224 --- /dev/null +++ b/tests/functional/70.asm @@ -0,0 +1,422 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld a, 10 + ld (_b), a + call __U8TOFREG + call SQRT + call EXP + call LN + res 7, e + call TAN + call COS + call SIN + ld hl, _a + call __STOREF + ld a, (_a) + ld de, (_a + 1) + ld bc, (_a + 3) + call __FTOU32REG + ld a, l + ld (_b), a + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "cos.asm" + +#line 1 "stackf.asm" + + ; ------------------------------------------------------------- + ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC + ; ------------------------------------------------------------- + + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) + __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) + +__FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) + ; Second argument to push into the stack calculator is popped out of the stack + ; Since the caller routine also receives the parameters into the top of the stack + ; four bytes must be removed from SP before pop them out + + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK + exx + pop hl ; Caller-Caller return addr + exx + pop hl ; Caller return addr + + pop af + pop de + pop bc + + push hl ; Caller return addr + exx + push hl ; Caller-Caller return addr + exx + + jp __FPSTACK_PUSH + + +__FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK + ; This format is specified in the ZX 48K Manual + ; You can push a 16 bit signed integer as + ; 0 SS LL HH 0, being SS the sign and LL HH the low + ; and High byte respectively + ld a, h + rla ; sign to Carry + sbc a, a ; 0 if positive, FF if negative + ld e, a + ld d, l + ld c, h + xor a + ld b, a + jp __FPSTACK_PUSH +#line 2 "cos.asm" + +COS: ; Computes COS using ROM FP-CALC + call __FPSTACK_PUSH + + rst 28h ; ROM CALC + defb 20h ; COS + defb 38h ; END CALC + + jp __FPSTACK_POP + +#line 36 "70.bas" +#line 1 "exp.asm" + + + +EXP: ; Computes e^n using ROM FP-CALC + call __FPSTACK_PUSH + + rst 28h ; ROM CALC + defb 26h ; E^n + defb 38h ; END CALC + + jp __FPSTACK_POP + +#line 37 "70.bas" +#line 1 "ftou32reg.asm" + +#line 1 "neg32.asm" + +__ABS32: + bit 7, d + ret z + +__NEG32: ; Negates DEHL (Two's complement) + ld a, l + cpl + ld l, a + + ld a, h + cpl + ld h, a + + ld a, e + cpl + ld e, a + + ld a, d + cpl + ld d, a + + inc l + ret nz + + inc h + ret nz + + inc de + ret + +#line 2 "ftou32reg.asm" + +__FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + ; Output: DEHL 32 bit number (signed) + PROC + + LOCAL __IS_FLOAT + + or a + jr nz, __IS_FLOAT + ; Here if it is a ZX ROM Integer + + ld h, c + ld l, d + ld a, e ; Takes sign: FF = -, 0 = + + ld de, 0 + inc a + jp z, __NEG32 ; Negates if negative + ret + +__IS_FLOAT: ; Jumps here if it is a true floating point number + ld h, e + push hl ; Stores it for later (Contains Sign in H) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + ;ld a, c ; Get exponent + sub 128 ; Exponent -= 128 + jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + +__FTOU32REG_LOOP: + exx ; Shift C'B' E'D' << 1, output bit stays in Carry + sla d + rl e + rl b + rl c + + exx ; Shift DEHL << 1, inserting the carry on the right + rl l + rl h + rl e + rl d + + djnz __FTOU32REG_LOOP + +__FTOU32REG_END: + pop af ; Take the sign bit + or a ; Sets SGN bit to 1 if negative + jp m, __NEG32 ; Negates DEHL + + ret + + ENDP + + +__FTOU8: ; Converts float in C ED LH to Unsigned byte in A + call __FTOU32REG + ld a, l + ret + +#line 38 "70.bas" +#line 1 "logn.asm" + + + +LN: ; Computes Ln(x) using ROM FP-CALC + call __FPSTACK_PUSH + + rst 28h ; ROM CALC + defb 20h ; 25h + defb 38h ; END CALC + + jp __FPSTACK_POP + +#line 39 "70.bas" +#line 1 "sin.asm" + + + +SIN: ; Computes SIN using ROM FP-CALC + call __FPSTACK_PUSH + + rst 28h ; ROM CALC + defb 1Fh + defb 38h ; END CALC + + jp __FPSTACK_POP + +#line 40 "70.bas" +#line 1 "sqrt.asm" + + + +SQRT: ; Computes SQRT(x) using ROM FP-CALC + call __FPSTACK_PUSH + + rst 28h ; ROM CALC + defb 28h ; SQRT + defb 38h ; END CALC + + jp __FPSTACK_POP + +#line 41 "70.bas" +#line 1 "storef.asm" + +__PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) + push de + ex de, hl ; DE <- HL + push ix + pop hl ; HL <- IX + add hl, de ; HL <- IX + HL + pop de + +__ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register + ex af, af' + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex af, af' + +__STOREF: ; Stores the given FP number in A EDCB at address HL + ld (hl), a + inc hl + ld (hl), e + inc hl + ld (hl), d + inc hl + ld (hl), c + inc hl + ld (hl), b + ret + +#line 42 "70.bas" +#line 1 "tan.asm" + + + +TAN: ; Computes TAN using ROM FP-CALC + call __FPSTACK_PUSH + + rst 28h ; ROM CALC + defb 21h ; TAN + defb 38h ; END CALC + + jp __FPSTACK_POP + +#line 43 "70.bas" +#line 1 "u32tofreg.asm" + + +__I8TOFREG: + ld l, a + rlca + sbc a, a ; A = SGN(A) + ld h, a + ld e, a + ld d, a + +__I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) + ; to a Floating Point Number returned in (A ED CB) + + ld a, d + or a ; Test sign + + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __U32TOFREG ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + +__U8TOFREG: + ; Converts an unsigned 8 bit (A) to Floating point + ld l, a + ld h, 0 + ld e, h + ld d, h + +__U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in A ED CB + + PROC + + LOCAL __U32TOFREG_END + + ld a, d + or e + or h + or l + ld b, d + ld c, e ; Returns 00 0000 0000 if ZERO + ret z + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 128 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + +__U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG + exx + ld a, d ; B'C'D'E' == 0 ? + or e + or b + or c + jp z, __U32TOFREG_END ; We are done + + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry + rr c + rr d + rr e + exx + + rr e ; Shift EDCB >> 1, inserting the carry on the left + rr d + rr c + rr b + + inc l ; Increment exponent + jp __U32TOFREG_LOOP + + +__U32TOFREG_END: + exx + ld a, l ; Puts the exponent in a + res 7, e ; Sets the sign bit to 0 (positive) + + ret + ENDP + +#line 44 "70.bas" + +ZXBASIC_USER_DATA: +_b: + DEFB 00 +_a: + DEFB 00, 00, 00, 00, 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/70.bas b/tests/functional/70.bas new file mode 100644 index 000000000..135a91b67 --- /dev/null +++ b/tests/functional/70.bas @@ -0,0 +1,5 @@ + +LET b = 10 +LET a = SIN COS TAN ABS LN EXP SQR b +LET b = a + diff --git a/tests/functional/funcnoparm.asm b/tests/functional/funcnoparm.asm new file mode 100644 index 000000000..f302619ea --- /dev/null +++ b/tests/functional/funcnoparm.asm @@ -0,0 +1,60 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld a, 1 + push af + call _xx + ld (_c), hl + ld a, 2 + push af + call _xx + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +_xx: + push ix + ld ix, 0 + add ix, sp + ld a, (ix+5) + inc a + ld l, a + ld h, 0 +_xx__leave: + ld sp, ix + pop ix + exx + pop hl + ex (sp), hl + exx + ret + +ZXBASIC_USER_DATA: +_c: + DEFB 00, 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/funcnoparm.bas b/tests/functional/funcnoparm.bas new file mode 100644 index 000000000..662d1d47e --- /dev/null +++ b/tests/functional/funcnoparm.bas @@ -0,0 +1,8 @@ + +FUNCTION xx(a as Ubyte) as UInteger + RETURN a + 1 +END FUNCTION + +LET c = xx 1 +xx 2 + diff --git a/tests/functional/funcnoparm2.bas b/tests/functional/funcnoparm2.bas new file mode 100644 index 000000000..c0a8c54f3 --- /dev/null +++ b/tests/functional/funcnoparm2.bas @@ -0,0 +1,9 @@ + +FUNCTION xx(a as Ubyte, b as Ubyte) as UInteger + RETURN a + 1 +END FUNCTION + +LET c = xx 1, 2 +xx 2 3 + + diff --git a/tests/functional/test_.py b/tests/functional/test_.py index dba5b699e..c12b049f0 100755 --- a/tests/functional/test_.py +++ b/tests/functional/test_.py @@ -67,7 +67,8 @@ arrlabels11.bas:4: Initializer expression is not constant. >>> process_file('lexerr.bas') lexerr.bas:1: ignoring illegal character '%' -lexerr.bas:1: Syntax Error. Unexpected token '1.0' +lexerr.bas:1: warning: Using default implicit type 'float' for 'a' +lexerr.bas:1: Syntax Error. Unexpected token '%' >>> process_file('opt2_nogoto.bas') opt2_nogoto.bas:2: Undeclared label "nolabel" >>> process_file('nosub.bas') diff --git a/zxbparser.py b/zxbparser.py index e391cf673..03a5c7215 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -581,8 +581,6 @@ def p_var_decl_ini(p): def p_idlist_id(p): """ idlist : ID | ARRAY_ID - | SUB_ID - | FUNC_ID """ p[0] = [(p[1], p.lineno(1))] @@ -961,10 +959,6 @@ def p_lexpr(p): | LET ID EQ | ARRAY_ID EQ | LET ARRAY_ID EQ - | SUB_ID EQ - | LET SUB_ID EQ - | FUNC_ID EQ - | LET FUNC_ID EQ """ global LET_ASSIGNMENT @@ -1982,10 +1976,6 @@ def p_save_code(p): | SAVE expr ID CO | SAVE expr ARRAY_ID CO | SAVE expr ARRAY_ID NEWLINE - | SAVE expr FUNC_ID CO - | SAVE expr FUNC_ID NEWLINE - | SAVE expr SUB_ID CO - | SAVE expr SUB_ID NEWLINE """ if p[2].type_ != TYPE.string: @@ -2293,7 +2283,7 @@ def p_BNOT_expr(p): def p_lp_expr_rp(p): - """ expr : LP expr RP + """ bexpr : LP expr RP """ p[0] = p[2] @@ -2488,12 +2478,17 @@ def p_expr_funccall(p): def p_idcall_expr(p): - """ func_call : FUNC_ID arg_list + """ func_call : ID arg_list %prec UMINUS """ # This can be a function call or a string index p[0] = make_call(p[1], p.lineno(1), p[2]) if p[0] is None: return + if p[0].token in ('STRSLICE', 'VAR', 'STRING'): + entry = SYMBOL_TABLE.access_call(p[1], p.lineno(1)) + entry.accessed = True + return + # TODO: Check that arrays really needs kind=function to be set # Both array accesses and functions are tagged as functions # functions also has the class_ attribute set to 'function' @@ -2536,13 +2531,18 @@ def p_err_undefined_arr_access(p): def p_bexpr_func(p): - """ bexpr : FUNC_ID bexpr + """ bexpr : ID bexpr """ - args = make_arg_list(make_argument(p[1], p.lineno(0))) + args = make_arg_list(make_argument(p[2], p.lineno(0))) p[0] = make_call(p[1], p.lineno(1), args) if p[0] is None: return + if p[0].token in ('STRSLICE', 'VAR', 'STRING'): + entry = SYMBOL_TABLE.access_call(p[1], p.lineno(1)) + entry.accessed = True + return + # TODO: Check that arrays really needs kind=function to be set # Both array accesses and functions are tagged as functions # functions also has the class_ attribute set to 'function' @@ -2871,6 +2871,7 @@ def p_preproc_line_pop(p): OPTIONS.option(p[4]).pop() +# region INTERNAL FUNCTIONS # ---------------------------------------- # INTERNAL BASIC Functions # These will be implemented in the TRADuctor @@ -2890,7 +2891,7 @@ def p_expr_usr(p): def p_expr_rnd(p): """ bexpr : RND - | RND LP RP + | RND LP RP """ p[0] = make_builtin(p.lineno(1), 'RND', None, type_=TYPE.float_) @@ -2939,7 +2940,7 @@ def p_expr_lbound(p): def p_expr_lbound_expr(p): - """ expr : LBOUND LP ARRAY_ID COMMA expr RP + """ bexpr : LBOUND LP ARRAY_ID COMMA expr RP | UBOUND LP ARRAY_ID COMMA expr RP """ entry = SYMBOL_TABLE.access_array(p[3], p.lineno(3)) @@ -3098,83 +3099,30 @@ def p_sgn(p): p[0] = make_builtin(p.lineno(1), 'SGN', p[2], lambda x: sgn(x), type_=TYPE.byte_) -''' + # ---------------------------------------- -# Trigonometrics +# Trigonometrics and LN, EXP, SQR # ---------------------------------------- def p_expr_sin(p): - """ bexpr : SIN bexpr %prec UMINUS + """ bexpr : math_fn bexpr %prec UMINUS """ - p[0] = make_builtin(p.lineno(1), 'SIN', + p[0] = make_builtin(p.lineno(1), p[1], make_typecast(TYPE.float_, p[2], p.lineno(1)), lambda x: math.sin(x)) -def p_expr_cos(p): - """ bexpr : COS bexpr %prec UMINUS - """ - p[0] = make_builtin(p.lineno(1), 'COS', - make_typecast(TYPE.float_, p[2], p.lineno(1)), - lambda x: math.cos(x)) - - -def p_expr_tan(p): - """ bexpr : TAN bexpr %prec UMINUS - """ - p[0] = make_builtin(p.lineno(1), 'TAN', - make_typecast(TYPE.float_, p[2], p.lineno(1)), - lambda x: math.tan(x)) - - -def p_expr_asin(p): - """ bexpr : ASN bexpr %prec UMINUS - """ - p[0] = make_builtin(p.lineno(1), 'ASN', - make_typecast(TYPE.float_, p[2], p.lineno(1)), - lambda x: math.asin(x)) - - -def p_expr_acos(p): - """ bexpr : ACS bexpr %prec UMINUS - """ - p[0] = make_builtin(p.lineno(1), 'ACS', - make_typecast(TYPE.float_, p[2], p.lineno(1)), - lambda x: math.acos(x)) - - -def p_expr_atan(p): - """ bexpr : ATN bexpr %prec UMINUS +def p_math_fn(p): + """ math_fn : SIN + | COS + | TAN + | ASN + | ACS + | ATN + | LN + | EXP + | SQR """ - p[0] = make_builtin(p.lineno(1), 'ATN', - make_typecast(TYPE.float_, p[2], p.lineno(1)), - lambda x: math.atan(x)) - - -# ---------------------------------------- -# Square root, Exponent and logarithms -# ---------------------------------------- -def p_expr_exp(p): - """ bexpr : EXP bexpr %prec UMINUS - """ - p[0] = make_builtin(p.lineno(1), 'EXP', - make_typecast(TYPE.float_, p[2], p.lineno(1)), - lambda x: math.exp(x)) - - -def p_expr_logn(p): - """ bexpr : LN bexpr %prec UMINUS - """ - p[0] = make_builtin(p.lineno(1), 'LN', - make_typecast(TYPE.float_, p[2], p.lineno(1)), - lambda x: math.log(x)) - - -def p_expr_sqrt(p): - """ bexpr : SQR bexpr %prec UMINUS - """ - p[0] = make_builtin(p.lineno(1), 'SQR', - make_typecast(TYPE.float_, p[2], p.lineno(1)), - lambda x: math.sqrt(x)) + p[0] = p[1] # ---------------------------------------- @@ -3195,7 +3143,10 @@ def p_abs(p): return p[0] = make_builtin(p.lineno(1), 'ABS', p[2], lambda x: x if x >= 0 else -x) -''' + +# endregion + + # ---------------------------------------- # The yyerror function # ---------------------------------------- @@ -3219,7 +3170,7 @@ def p_error(p): # ---------------------------------------- # Initialization # ---------------------------------------- -parser = yacc.yacc(method='LALR', tabmodule='parsetab.zxbtab') #, debug=OPTIONS.Debug.value > 2) +parser = yacc.yacc(method='LALR', tabmodule='parsetab.zxbtab', debug=OPTIONS.Debug.value > 2) ast = None data_ast = None # Global Variables AST optemps = OpcodesTemps() From 0732c30e796b94585860f9cb3e38cfd29fefb058 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 2 Oct 2017 01:17:37 +0200 Subject: [PATCH 066/247] bugfix: better management for labels Syntax change. A new ID alone is now a label ALWAYS, unless it's been already defined. --- zxbparser.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/zxbparser.py b/zxbparser.py index 03a5c7215..d8efa849f 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -487,12 +487,6 @@ def p_program_line_label(p): p[0] = make_block(make_label(p[1], p.lineno(1)), p[2]) -def p_program_line_label2(p): - """ program_line : ID CO NEWLINE - """ - p[0] = make_label(p[1], p.lineno(1)) - - def p_var_decl(p): """ var_decl : DIM idlist typedef NEWLINE | DIM idlist typedef CO @@ -885,7 +879,11 @@ def p_statement_call(p): if p[2] is None: p[0] = None elif len(p) == 3: - p[0] = make_sub_call(p[1], p.lineno(1), make_arg_list(None)) + entry = SYMBOL_TABLE.get_entry(p[1]) + if not entry or entry.class_ in (CLASS.label, CLASS.unknown): + p[0] = make_label(p[1], p.lineno(1)) + else: + p[0] = make_sub_call(p[1], p.lineno(1), make_arg_list(None)) else: p[0] = make_sub_call(p[1], p.lineno(1), p[2]) From ed889a28c3d72d847a5f6859b7baf28dc79bc54a Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 20 Sep 2017 21:36:24 +0200 Subject: [PATCH 067/247] add READ, DATA, RESTORE tokens --- keywords.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/keywords.py b/keywords.py index f158be905..f4ecdcf6a 100755 --- a/keywords.py +++ b/keywords.py @@ -89,8 +89,10 @@ 'poke': 'POKE', 'print': 'PRINT', 'randomize': 'RANDOMIZE', - 'rnd': 'RND', + 'read': 'READ', + 'restore': 'RESTORE', 'return': 'RETURN', + 'rnd': 'RND', 'save': 'SAVE', 'sgn': 'SGN', 'shl': 'SHL', From bce667fc1a1a0b52cd5e2eebfa1c0d22d843a241 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 22 Sep 2017 19:34:21 +0200 Subject: [PATCH 068/247] Add syntax rules for READ, DATA, RESTORE --- zxbparser.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/zxbparser.py b/zxbparser.py index d8efa849f..7d22ff45c 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -1534,6 +1534,36 @@ def p_do_loop_until(p): api.errmsg.warning_empty_loop(p.lineno(3)) +def p_data(p): + """ statement : DATA arguments CO + | DATA arguments NEWLINE + """ + + +def p_restore(p): + """ statement : RESTORE CO + | RESTORE NEWLINE + """ + + +def p_restore_id(p): + """ statement : RESTORE ID CO + | RESTORE ID NEWLINE + """ + + +def p_read(p): + """ statement : READ ID CO + | READ ID NEWLINE + """ + + +def p_read_arr(p): + """ statement : READ ARRAY_ID arg_list CO + | READ ARRAY_ID arg_list NEWLINE + """ + + def p_do_loop_while(p): """ statement : do_start program label_loop WHILE expr CO | do_start program label_loop WHILE expr NEWLINE From 2e86ab1a40d33e92693111605faa5d919d57913c Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 23 Sep 2017 11:02:03 +0200 Subject: [PATCH 069/247] refact: use api.errmsg for an error "Cannot assign a value to 'x'. It's not a variable" is now in a syntax_error_.. function --- api/errmsg.py | 8 ++++++++ tests/functional/errletfunc.bas | 6 ++++++ tests/functional/test_.py | 2 ++ zxbparser.py | 2 +- 4 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/functional/errletfunc.bas diff --git a/api/errmsg.py b/api/errmsg.py index 991114a83..f41480c18 100644 --- a/api/errmsg.py +++ b/api/errmsg.py @@ -151,7 +151,15 @@ def syntax_error_is_a_sub_not_a_func(lineno, name): syntax_error(lineno, "'%s' is SUBROUTINE not a FUNCTION" % name) +# ---------------------------------------- +# Syntax error: strict mode: missing type declaration # ---------------------------------------- def syntax_error_undeclared_type(lineno, id_): syntax_error(lineno, "strict mode: missing type declaration for '%s'" % id_) + + +# ---------------------------------------- +# Cannot assign a value to 'var'. It's not a variable # ---------------------------------------- +def syntax_error_cannot_assing_not_a_var(lineno, id_): + syntax_error(lineno, "Cannot assign a value to '%s'. It's not a variable" % id_) diff --git a/tests/functional/errletfunc.bas b/tests/functional/errletfunc.bas new file mode 100644 index 000000000..af5dcfb8f --- /dev/null +++ b/tests/functional/errletfunc.bas @@ -0,0 +1,6 @@ + +SUB x +END SUB + +let x = 1 + diff --git a/tests/functional/test_.py b/tests/functional/test_.py index c12b049f0..c7f8f286f 100755 --- a/tests/functional/test_.py +++ b/tests/functional/test_.py @@ -92,6 +92,8 @@ >>> process_file('strict.bas') strict.bas:2: warning: Using default implicit type 'float' for 'b' strict.bas:4: strict mode: missing type declaration for 'a' +>>> process_file('errletfunc.bas') +errletfunc.bas:5: Cannot assign a value to 'x'. It's not a variable """ diff --git a/zxbparser.py b/zxbparser.py index 7d22ff45c..7b9a37d5f 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -914,7 +914,7 @@ def p_assignment(p): variable.class_ = CLASS.var if variable.class_ not in (CLASS.var, CLASS.array): - syntax_error(p.lineno(i), "Cannot assign a value to '%s'. It's not a variable" % variable.name) + api.errmsg.syntax_error_cannot_assing_not_a_var(p.lineno(i), variable.name) return if variable.class_ == CLASS.var and q1class_ == CLASS.array: From 1c55120cc2d9b5bf6f019422d8e3987c318576cd Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 30 Sep 2017 01:18:33 +0200 Subject: [PATCH 070/247] allows double quote "" inside strings This allows to specify quotes inside strings. Ej. "Hello ""Joan""" in the asm source code represents the string 'Hello "Joan"' --- asmlex.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/asmlex.py b/asmlex.py index ae6e734d3..df66da78c 100755 --- a/asmlex.py +++ b/asmlex.py @@ -352,8 +352,8 @@ def t_APO(self, t): return t def t_INITIAL_preproc_STRING(self, t): - r'"[^"]*"' # a doubled quoted string - t.value = t.value[1:-1] # Remove quotes + r'"(""|[^"])*"' # a doubled quoted string + t.value = t.value[1:-1].replace('""', '"') # Remove quotes return t def t_INITIAL_preproc_error(self, t): From 850cc09616b5bc01fd9ee9b1d8e60319d166060b Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 23 Sep 2017 01:31:10 +0200 Subject: [PATCH 071/247] Add support for different number types All types supported with on the fly conversion / promotion when required. --- api/global_.py | 9 + api/utils.py | 7 + arch/zx48k/backend/__init__.py | 44 ++++- arch/zx48k/translator.py | 118 +++++++++-- library-asm/read_restore.asm | 350 +++++++++++++++++++++++++++++++++ symbols/argument.py | 2 +- symbols/funcdecl.py | 4 +- tests/functional/read0.bas | 14 ++ tests/functional/read1.bas | 13 ++ tests/functional/read2.bas | 13 ++ tests/functional/read3.bas | 12 ++ tests/runtime/readokdown.bas | 43 ++++ tests/runtime/readokup.bas | 43 ++++ zxb.py | 5 + zxbparser.py | 107 ++++++++-- 15 files changed, 753 insertions(+), 31 deletions(-) create mode 100644 library-asm/read_restore.asm create mode 100644 tests/functional/read0.bas create mode 100644 tests/functional/read1.bas create mode 100644 tests/functional/read2.bas create mode 100644 tests/functional/read3.bas create mode 100644 tests/runtime/readokdown.bas create mode 100644 tests/runtime/readokup.bas diff --git a/api/global_.py b/api/global_.py index e9cbbc7b2..834977af3 100644 --- a/api/global_.py +++ b/api/global_.py @@ -136,3 +136,12 @@ # Default optimization level # ---------------------------------------------------------------------- DEFAULT_OPTIMIZATION_LEVEL = 2 # Optimization level. Higher -> more optimized + +# ---------------------------------------------------------------------- +# DATA blocks +# ---------------------------------------------------------------------- +DATAS = [] +DATA_LABELS = {} # Maps declared labels to current data ptr +DATA_PTR_CURRENT = None +DATA_IS_USED = False +DATA_FUNCTIONS = [] # Counts the number of funcptr emmited diff --git a/api/utils.py b/api/utils.py index 6e0ef793f..1852f41be 100644 --- a/api/utils.py +++ b/api/utils.py @@ -53,3 +53,10 @@ def sanitize_filename(fname): This is to make all BASIC programs compatible in all OSes """ return fname.replace('\\', '/') + + +def current_data_label(): + """ Returns a data label to which all labels must point to, until + a new DATA line is declared + """ + return '__DATA__{0}'.format(len(global_.DATAS)) diff --git a/arch/zx48k/backend/__init__.py b/arch/zx48k/backend/__init__.py index fe84af6ee..e0e69a286 100644 --- a/arch/zx48k/backend/__init__.py +++ b/arch/zx48k/backend/__init__.py @@ -85,6 +85,7 @@ # External functions from ..optimizer import oper, inst, condition, HI16, LO16, is_16bit_idx_register from api.config import OPTIONS +import api.fp __all__ = [ '_fpop', @@ -429,6 +430,45 @@ def _deflabel(ins): return ['%s EQU %s' % (str(ins.quad[1]), str(ins.quad[2]))] +def _data(ins): + """ Defines a data item (bynary). + It's just a constant expression to be converted do binary data "as is" + + 1st parameter is the type-size (u8 or i8 for byte, u16 or i16 for word, etc) + 2nd parameter is the list of expressions. All of them will be converted to the + type required. + """ + output = [] + t = ins.quad[1] + q = eval(ins.quad[2]) + + if t in ('i8', 'u8'): + size = 'B' + elif t in ('i16', 'u16'): + size = 'W' + elif t in ('i32', 'u32'): + size = 'W' + z = list() + for expr in ins.quad[2]: + z.extend(['(%s) & 0xFFFF' % expr, '(%s) >> 16' % expr]) + q = z + elif t == 'str': + size = "B" + q = ['"%s"' % x.replace('"', '""') for x in q] + elif t == 'f': + dat_ = [api.fp.immediate_float(float(x)) for x in q] + for x in dat_: + output.extend(['DEFB %s' % x[0], 'DEFW %s, %s' % (x[1], x[2])]) + return output + else: + raise InvalidIC(ins.quad, 'Unimplemented data size %s for %s' % (t, q)) + + for x in q: + output.append('DEF%s %s' % (size, x)) + + return output + + def _var(ins): """ Defines a memory variable. """ @@ -1696,7 +1736,7 @@ class Quad(object): def __init__(self, *args): """ Creates a quad-uple checking it has the current params. - Operatos should be passed as Quad('+', tSymbol, val1, val2) + Operators should be passed as Quad('+', tSymbol, val1, val2) """ if not args: raise InvalidIC('') @@ -1732,6 +1772,8 @@ def __str__(self): 'addstr': [3, _addstr], + 'data': [2, _data], + 'subi8': [3, _sub8], 'subu8': [3, _sub8], 'subi16': [3, _sub16], diff --git a/arch/zx48k/translator.py b/arch/zx48k/translator.py index d2290c5b7..06ce2e5c4 100644 --- a/arch/zx48k/translator.py +++ b/arch/zx48k/translator.py @@ -67,12 +67,37 @@ class TranslatorVisitor(NodeVisitor): STRING_LABELS = OrderedDict() JUMP_TABLES = [] + # Type code used in DATA + DATA_TYPES = { + 'str': 1, + 'i8': 2, + 'u8': 3, + 'i16': 4, + 'u16': 5, + 'i32': 6, + 'u32': 7, + 'f16': 8, + 'f': 9 + } + @classmethod def reset(cls): cls.LOOPS = [] # Defined LOOPS cls.STRING_LABELS = OrderedDict() cls.JUMP_TABLES = [] + def add_string_label(self, str_): + """ Maps ("folds") the given string, returning an unique label ID. + This allows several constant labels to be initialized to the same address + thus saving memory space. + :param str_: the string to map + :return: the unique label ID + """ + if self.STRING_LABELS.get(str_, None) is None: + self.STRING_LABELS[str_] = backend.tmp_label() + + return self.STRING_LABELS[str_] + @property def O_LEVEL(self): return OPTIONS.optimization.value @@ -140,6 +165,33 @@ def visit_ATTR_TMP(self, node): ifile = ifile[:ifile.index('_')] backend.REQUIRES.add(ifile + '.asm') + # This function must be called before emit_strings + def emit_data_blocks(self): + if not gl.DATA_IS_USED: + return # nothing to do + + for label_, datas in gl.DATAS: + self.emit('label', label_) + for d in datas: + if isinstance(d, symbols.FUNCDECL): + type_ = '%02Xh' % (self.DATA_TYPES[self.TSUFFIX(d.type_)] | 0x80) + self.emit('data', self.TSUFFIX(TYPE.byte_), [type_]) + self.emit('data', self.TSUFFIX(gl.PTR_TYPE), [d.mangled]) + continue + + self.emit('data', self.TSUFFIX(TYPE.byte_), [self.DATA_TYPES[self.TSUFFIX(d.value.type_)]]) + if d.value.type_ == self.TYPE(TYPE.string): + lbl = self.add_string_label(d.value.value) + self.emit('data', self.TSUFFIX(api.global_.PTR_TYPE), [lbl]) + elif d.value.type_ == self.TYPE(TYPE.fixed): # Convert to bytes + bytes_ = 0xFFFFFFFF & int(d.value.value * 2 ** 16) + self.emit('data', self.TSUFFIX(TYPE.uinteger), + ['0x%04X' % (bytes_ & 0xFFFF), '0x%04X' % (bytes_ >> 16)]) + else: + self.emit('data', self.TSUFFIX(d.value.type_), [self.traverse_const(d.value)]) + + self.emit('vard', '__DATA__END', ['00']) + def emit_strings(self): for str_, label_ in self.STRING_LABELS.items(): l = '%04X' % (len(str_) & 0xFFFF) # TODO: Universalize for any arch @@ -262,10 +314,7 @@ def visit_NUMBER(self, node): def visit_STRING(self, node): __DEBUG__('STRING ' + str(node)) - if self.STRING_LABELS.get(node.value, None) is None: - self.STRING_LABELS[node.value] = backend.tmp_label() - - node.t = '#' + self.STRING_LABELS[node.value] + node.t = '#' + self.add_string_label(node.value) yield node.t def visit_END(self, node): @@ -584,6 +633,46 @@ def visit_FUNCCALL(self, node): self.emit('call', node.entry.mangled, node.entry.size) + def visit_RESTORE(self, node): + if not gl.DATA_IS_USED: + return # If no READ is used, ignore all DATA related statements + lbl = gl.DATA_LABELS[node.args[0].name] + self.emit('fparam' + self.TSUFFIX(node.args[0].type_), '#' + lbl) + self.emit('call', '__RESTORE', 0) + backend.REQUIRES.add('read_restore.asm') + + def visit_READ(self, node): + self.emit('fparamu8', '#' + str(self.DATA_TYPES[self.TSUFFIX(node.args[0].type_)])) + self.emit('call', '__READ', node.args[0].type_.size) + + if isinstance(node.args[0], symbols.ARRAYACCESS): + arr = node.args[0] + t = api.global_.optemps.new_t() + scope = arr.scope + suf = self.TSUFFIX(arr.type_) + + if arr.offset is None: + yield arr + + if scope == SCOPE.global_: + self.emit('astore' + suf, arr.entry.mangled, t) + elif scope == SCOPE.parameter: + self.emit('pastore' + suf, arr.entry.offset, t) + elif scope == SCOPE.local: + self.emit('pastore' + suf, -arr.entry.offset, t) + else: + name = arr.entry.mangled + if scope == SCOPE.global_: + self.emit('store' + suf, '%s + %i' % (name, arr.offset), t) + elif scope == SCOPE.parameter: + self.emit('pstore' + suf, arr.entry.offset - arr.offset, t) + elif scope == SCOPE.local: + self.emit('pstore' + suf, -(arr.entry.offset - arr.offset), t) + + else: + self.emit_var_assign(node.args[0], t=api.global_.optemps.new_t()) + backend.REQUIRES.add('read_restore.asm') + # region Control Flow Sentences # ----------------------------------------------------------------------------------------------------- # Control Flow Compound sentences FOR, IF, WHILE, DO UNTIL... @@ -1017,14 +1106,12 @@ def visit_ASM(self, node): # -------------------------------------- # Helpers # -------------------------------------- - def emit_let_left_part(self, node, t=None): - var = node.children[0] - expr = node.children[1] + def emit_var_assign(self, var, t): + """ Emits code for storing a value into a variable + :param var: variable (node) to be updated + :param t: the value to emmit (e.g. a _label, a const, a tN...) + """ p = '*' if var.byref else '' # Indirection prefix - - if t is None: - t = expr.t # TODO: Check - if self.O_LEVEL > 1 and not var.accessed: return @@ -1040,6 +1127,15 @@ def emit_let_left_part(self, node, t=None): var.offset -= 1 + 2 * var.alias.count self.emit('pstore' + self.TSUFFIX(var.type_), p + str(-var.offset), t) + def emit_let_left_part(self, node, t=None): + var = node.children[0] + expr = node.children[1] + + if t is None: + t = expr.t # TODO: Check + + return self.emit_var_assign(var, t) + # endregion # region [Static Methods] diff --git a/library-asm/read_restore.asm b/library-asm/read_restore.asm new file mode 100644 index 000000000..a31de87c0 --- /dev/null +++ b/library-asm/read_restore.asm @@ -0,0 +1,350 @@ +;; This implements READ & RESTORE functions +;; Reads a new element from the DATA Address code +;; Updates the DATA_ADDR read ptr for the next read + +;; Data codification is 1 byte for type followed by data bytes +;; Byte type is encoded as follows + +;; 00: End of data +;; 01: String +;; 02: Byte +;; 03: Ubyte +;; 04: Integer +;; 05: UInteger +;; 06: Long +;; 07: ULong +;; 08: Fixed +;; 09: Float + +;; bit7 is set for a parameter-less function +;; In that case, the next two bytes are the ptr of the function to jump + +#include once +#include once +#include once +#include once +#include once +#include once +#include once + +#define _str 1 +#define _i8 2 +#define _u8 3 +#define _i16 4 +#define _u16 5 +#define _i32 6 +#define _u32 7 +#define _f16 8 +#define _flt 9 + + +;; Updates restore point to the given HL mem. address +__RESTORE: + PROC + LOCAL __DATA_ADDR + + ld (__DATA_ADDR), hl + ret + +;; Reads a value from the DATA mem area and updates __DATA_ADDR ptr to the +;; next item. On Out Of Data, restarts +;; +__READ: + LOCAL read_restart, cont, cont2, table, no_func + LOCAL dynamic_cast, dynamic_cast2, dynamic_cast3, dynamic_cast4 + LOCAL _decode_table, coerce_to_int, coerce_to_int2, promote_to_i16 + LOCAL _from_i8, _from_u8 + LOCAL _from_i16, _from_u16 + LOCAL _from_i32, _from_u32 + LOCAL _from_fixed, __data_error + + push af ; type of data to read + ld hl, (__DATA_ADDR) +read_restart: + ld a, (hl) + or a ; 0 => OUT of data + jr nz, cont + ;; Signals out of data + + ld hl, __DATA__0 + ld (__DATA_ADDR), hl + jr read_restart ; Start again +cont: + and 0x80 + ld a, (hl) + push af + jp z, no_func ;; Loads data directly, not a function + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl +cont2: + ld de, dynamic_cast + push de ; ret address + jp (hl) ; "call (hl)" + + ;; Now tries to convert the given result to the expected type or raise an error +dynamic_cast: + exx + ex af, af' + pop af ; type READ + and 0x7F ; clear bit 7 + pop hl ; type requested by USER (type of the READ variable) + ld c, h ; save requested type (save it in register C) + cp h + exx + jr nz, dynamic_cast2 ; Types are identical? + ;; yes, they are + ex af, af' + ret + +dynamic_cast2: + cp _str ; Requested a number, but read a string? + jr nz, dynamic_cast3 + call __MEM_FREE ; Frees str from memory + jr __data_error + +dynamic_cast3: + exx + ld b, a ; Read type + ld a, c ; Requested type + cp _str + jr z, __data_error + cp b + jr c, dynamic_cast4 + ;; here the user expected type is "larger" than the read one + ld a, b + sub _i8 + add a, a + ld l, a + ld h, 0 + ld de, _decode_table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl + ld a, c ; Requested type + exx + ret + +__data_error: + ;; When a data is read, but cannot be converted to the requested type + ;; that is, the user asked for a string and we read a number or vice versa + ld a, ERROR_InvalidArg + call __STOP ; The user expected a string, but read a number + xor a + ld h, a + ld l, a + ld e, a + ld d, a + ld b, a + ld c, a + ret + +_decode_table: + dw _from_i8 + dw _from_u8 + dw _from_i16 + dw _from_u16 + dw _from_i32 + dw _from_u32 + dw _from_fixed + +_from_i8: + cp _i16 + jr nc, promote_to_i16 + ex af, af' + ret ;; Was from Byte to Ubyte + +promote_to_i16: + ex af, af' + ld l, a + rla + sbc a, a + ld h, a ; copy sgn to h + ex af, af' + jr _before_from_i16 + +_from_u8: + ex af, af' + ld l, a + ld h, 0 + ex af, af' + ;; Promoted to i16 + +_before_from_i16: +_from_i16: + cp _i32 + ret c ;; from i16 to u16 + ;; Promote i16 to i32 + ex af, af' + ld a, h + rla + sbc a, a + ld e, a + ld d, a + ex af, af' +_from_i32: + cp _u32 + ret z ;; From i32 to u32 + ret c ;; From u16 to i32 + cp _flt + jp z, __I32TOFREG +_from_u32: + cp _flt + jp z, __U32TOFREG + ex de, hl + ld hl, 0 + cp _f16 + ret z +_from_fixed: ;; From fixed to float + jp __F16TOFREG +_from_u16: + ld de, 0 ; HL 0x0000 => 32 bits + jp _from_i32 + +dynamic_cast4: + ;; The user type is "shorter" than the read one + cp _f16 ;; required type + jr c, before_to_int ;; required < fixed (f16) + ex af, af' + exx ;; Ok, we must convert from float to f16 + jp __FTOF16REG + +before_to_int: + ld a, b ;; read type + cp _f16 ;; + jr nz, coerce_to_int ;; From float to int + ld a, c ;; user type + exx + ;; f16 to Long + ex de, hl + ld a, h + rla + sbc a, a + ld d, a + ld e, a + exx + jr coerce_to_int2 +coerce_to_int: + exx + ex af, af' + call __FTOU32REG + ex af, af' ; a contains user type + exx +coerce_to_int2: ; At this point we have an u/integer in hl + exx + cp _i16 + ret nc ; Already done. Return the result + ld a, l ; Truncate to byte + ret + +no_func: + exx + ld de, dynamic_cast + push de ; Ret address + dec a ; 0 => string; 1, 2 => byte; 3, 4 => integer; 5, 6 => long, 7 => fixed; 8 => float + ld h, 0 + add a, a + ld l, a + ld de, table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl ; address to jump to + exx + inc hl + ret ; jp (sp) => jump to table[a - 1] + +table: + LOCAL __01_decode_string + LOCAL __02_decode_byte + LOCAL __03_decode_ubyte + LOCAL __04_decode_integer + LOCAL __05_decode_uinteger + LOCAL __06_decode_long + LOCAL __07_decode_ulong + LOCAL __08_decode_fixed + LOCAL __09_decode_float + + ;; 1 -> Decode string + ;; 2, 3 -> Decode Byte, UByte + ;; 4, 5 -> Decode Integer, UInteger + ;; 6, 7 -> Decode Long, ULong + ;; 8 -> Decode Fixed + ;; 9 -> Decode Float + dw __01_decode_string + dw __02_decode_byte + dw __03_decode_ubyte + dw __04_decode_integer + dw __05_decode_uinteger + dw __06_decode_long + dw __07_decode_ulong + dw __08_decode_fixed + dw __09_decode_float + +__01_decode_string: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl + jp __LOADSTR + +__02_decode_byte: +__03_decode_ubyte: + ld a, (hl) + inc hl + ld (__DATA_ADDR), hl + ret + +__04_decode_integer: +__05_decode_uinteger: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl + ex de, hl + ret + +__06_decode_long: +__07_decode_ulong: +__08_decode_fixed: + ld b, h + ld c, l + inc bc + inc bc + inc bc + inc bc + ld (__DATA_ADDR), bc + jp __ILOAD32 + +__09_decode_float: + call __LOADF + inc hl + ld (__DATA_ADDR), hl + ld h, a ; returns A in H; sets A free + ret + +__DATA_ADDR: ;; Stores current DATA ptr + dw __DATA__0 + ENDP + +#undef _str +#undef _i8 +#undef _u8 +#undef _i16 +#undef _u16 +#undef _i32 +#undef _u32 +#undef _f16 +#undef _flt diff --git a/symbols/argument.py b/symbols/argument.py index 502203252..f375c03c3 100644 --- a/symbols/argument.py +++ b/symbols/argument.py @@ -87,7 +87,7 @@ def __eq__(self, other): def typecast(self, type_): """ Test type casting to the argument expression. - On sucess changes the node value to the new typecast, and returns + On success changes the node value to the new typecast, and returns True. On failure, returns False, and the node value is set to None. """ self.value = SymbolTYPECAST.make_node(type_, self.value, self.lineno) diff --git a/symbols/funcdecl.py b/symbols/funcdecl.py index 89c52fcf5..68c5d185a 100644 --- a/symbols/funcdecl.py +++ b/symbols/funcdecl.py @@ -69,10 +69,10 @@ def mangled(self): return self.entry.mangled @classmethod - def make_node(cls, func_name, lineno): + def make_node(cls, func_name, lineno, type_=None): """ This will return a node with the symbol as a function. """ - entry = global_.SYMBOL_TABLE.declare_func(func_name, lineno) + entry = global_.SYMBOL_TABLE.declare_func(func_name, lineno, type_=type_) if entry is None: return None diff --git a/tests/functional/read0.bas b/tests/functional/read0.bas new file mode 100644 index 000000000..9431c6b65 --- /dev/null +++ b/tests/functional/read0.bas @@ -0,0 +1,14 @@ +REM Error x is not a var + +DIM v as Float = 1 + +RESTORE + +DATA 10, 25 * v, SIN(v) * tan(v)^2 + +SUB x +END SUB + +READ x + + diff --git a/tests/functional/read1.bas b/tests/functional/read1.bas new file mode 100644 index 000000000..eccaf62fd --- /dev/null +++ b/tests/functional/read1.bas @@ -0,0 +1,13 @@ +REM Error x is an array, not an scalar + +DIM v as Float = 1 + +RESTORE + +DATA 10, 25 * v, SIN(v) * tan(v)^2 + +DIM x(5) as UByte + +READ x + + diff --git a/tests/functional/read2.bas b/tests/functional/read2.bas new file mode 100644 index 000000000..b04721a61 --- /dev/null +++ b/tests/functional/read2.bas @@ -0,0 +1,13 @@ +REM Error x is an array, not an scalar + +DIM v as Float = 1 +DIM x(3) + +RESTORE + +DATA 10, 25 * v, SIN(v) * tan(v)^2, "Hello" + + +READ x + + diff --git a/tests/functional/read3.bas b/tests/functional/read3.bas new file mode 100644 index 000000000..194f9ee08 --- /dev/null +++ b/tests/functional/read3.bas @@ -0,0 +1,12 @@ +REM Error x is an array, not an scalar + +DIM v as Float = 1 + +RESTORE + +DATA 10, 25 * v, SIN(v) * tan(v)^2, "Hello" + +READ x(5) + + + diff --git a/tests/runtime/readokdown.bas b/tests/runtime/readokdown.bas new file mode 100644 index 000000000..fbfc548a4 --- /dev/null +++ b/tests/runtime/readokdown.bas @@ -0,0 +1,43 @@ +REM Type coerding (reduction) in read DATA + +DIM i8 as Byte +DIM u8 as UByte +DIM i16 as Integer +DIM u16 as UInteger +DIM i32 as Long +DIM u32 as ULong +DIM f16 as Fixed +DIM flt as Float + +RESTORE +READ i8 +PRINT i8 +RESTORE +READ u8 +PRINT u8 + +RESTORE +READ i16 +PRINT i16 +RESTORE +READ u16 +PRINT u16 + +RESTORE +READ i32 +PRINT i32 +RESTORE +READ u32 +PRINT u32 + +RESTORE +READ f16 +PRINT f16 + +RESTORE +READ flt +PRINT flt + +DATA -1.5 + + diff --git a/tests/runtime/readokup.bas b/tests/runtime/readokup.bas new file mode 100644 index 000000000..15efcded0 --- /dev/null +++ b/tests/runtime/readokup.bas @@ -0,0 +1,43 @@ +REM Type promoting in read DATA + +DIM i8 as Byte +DIM u8 as UByte +DIM i16 as Integer +DIM u16 as UInteger +DIM i32 as Long +DIM u32 as ULong +DIM f16 as Fixed +DIM flt as Float + +RESTORE +READ i8 +PRINT i8 +RESTORE +READ u8 +PRINT u8 + +RESTORE +READ i16 +PRINT i16 +RESTORE +READ u16 +PRINT u16 + +RESTORE +READ i32 +PRINT i32 +RESTORE +READ u32 +PRINT u32 + +RESTORE +READ f16 +PRINT f16 + +RESTORE +READ flt +PRINT flt + +DATA -1 + + diff --git a/zxb.py b/zxb.py index a2483cbf7..b7408b507 100755 --- a/zxb.py +++ b/zxb.py @@ -250,10 +250,15 @@ def main(args=None): translator = arch.zx48k.Translator() translator.visit(zxbparser.ast) + if gl.DATA_IS_USED: + gl.FUNCTIONS.extend(gl.DATA_FUNCTIONS) + # This will fill MEMORY with pending functions func_visitor = arch.zx48k.FunctionTranslator(gl.FUNCTIONS) func_visitor.start() + # Emits data lines + translator.emit_data_blocks() # Emits default constant strings translator.emit_strings() # Emits jump tables diff --git a/zxbparser.py b/zxbparser.py index 7b9a37d5f..11970ac17 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -43,6 +43,7 @@ import api.errmsg import api.symboltable import api.config +import api.utils # Symbol Classes import symbols @@ -132,6 +133,13 @@ def init(): SYMBOL_TABLE = gl.SYMBOL_TABLE = api.symboltable.SymbolTable() OPTIONS = api.config.OPTIONS + # DATAs info + gl.DATA_LABELS.clear() + gl.DATA_IS_USED = False + del gl.DATAS[:] + gl.DATA_PTR_CURRENT = api.utils.current_data_label() + gl.DATA_FUNCTIONS = [] + # ---------------------------------------------------------------------- # "Macro" functions. Just return more complex expresions @@ -235,10 +243,10 @@ def make_array_declaration(entry): return symbols.ARRAYDECL(entry) -def make_func_declaration(func_name, lineno): +def make_func_declaration(func_name, lineno, type_=None): """ This will return a node with the symbol as a function. """ - return symbols.FUNCDECL.make_node(func_name, lineno) + return symbols.FUNCDECL.make_node(func_name, lineno, type_=type_) def make_arg_list(node, *args): @@ -371,7 +379,10 @@ def make_bound_list(node, *args): def make_label(id_, lineno): """ Creates a label entry. Returns None on error. """ - return SYMBOL_TABLE.declare_label(id_, lineno) + entry = SYMBOL_TABLE.declare_label(id_, lineno) + if entry: + gl.DATA_LABELS[id_] = gl.DATA_PTR_CURRENT # This label points to the current DATA block index + return entry # ---------------------------------------------------------------------- @@ -1538,30 +1549,95 @@ def p_data(p): """ statement : DATA arguments CO | DATA arguments NEWLINE """ + label_ = make_label(gl.DATA_PTR_CURRENT, lineno=p.lineno(1)) + datas_ = [] + funcs = [] + for d in p[2].children: + value = d.value + if is_static(value): + datas_.append(d) + continue + + new_lbl = '__DATA__FUNCPTR__{0}'.format(len(gl.DATA_FUNCTIONS)) + entry = make_func_declaration(new_lbl, p.lineno(1), type_=value.type_) + if not entry: + continue + + func = entry.entry + func.convention = CONVENTION.fastcall + SYMBOL_TABLE.enter_scope(new_lbl) + func.local_symbol_table = SYMBOL_TABLE.table[SYMBOL_TABLE.current_scope] + func.locals_size = SYMBOL_TABLE.leave_scope() + + gl.DATA_FUNCTIONS.append(func) + sent = make_sentence('RETURN', func, value) + func.body = make_block(sent) + datas_.append(entry) + funcs.append(entry) + + gl.DATAS.append([label_, datas_]) + id_ = api.utils.current_data_label() + gl.DATA_PTR_CURRENT = id_ def p_restore(p): """ statement : RESTORE CO | RESTORE NEWLINE - """ - - -def p_restore_id(p): - """ statement : RESTORE ID CO + | RESTORE ID CO | RESTORE ID NEWLINE + | RESTORE NUMBER CO + | RESTORE NUMBER NEWLINE """ + if len(p) == 3: + id_ = '__DATA__{0}'.format(len(gl.DATAS)) + else: + id_ = p[2] + + lbl = check_and_make_label(id_, p.lineno(2)) + p[0] = make_sentence('RESTORE', lbl) def p_read(p): - """ statement : READ ID CO - | READ ID NEWLINE + """ statement : READ arguments CO + | READ arguments NEWLINE """ + gl.DATA_IS_USED = True + reads = [] + for arg in p[2]: + entry = arg.value + if entry is None: + p[0] = None + return -def p_read_arr(p): - """ statement : READ ARRAY_ID arg_list CO - | READ ARRAY_ID arg_list NEWLINE - """ + if isinstance(entry, symbols.VARARRAY): + api.errmsg.syntax_error(p.lineno(1), "Cannot read '%s'. It's an array" % entry.name) + p[0] = None + return + + if isinstance(entry, symbols.VAR): + if entry.class_ != CLASS.var: + api.errmsg.syntax_error_cannot_assing_not_a_var(p.lineno(2), entry.name) + p[0] = None + return + + entry.accessed = True + if entry.type_ == TYPE.auto: + entry.type_ = _TYPE(gl.DEFAULT_TYPE) + api.errmsg.warning_implicit_type(p.lineno(2), p[2], entry.type_) + + reads.append(make_sentence('READ', entry)) + continue + + if isinstance(entry, symbols.ARRAYACCESS): + reads.append(make_sentence('READ', make_array_access(entry.entry.name, entry.lineno, entry.args))) + continue + + api.errmsg.syntax_error(p.lineno(1), "Syntax error. Can only read a variable or an array element") + p[0] = None + return + + p[0] = make_block(*reads) def p_do_loop_while(p): @@ -2619,8 +2695,7 @@ def p_funcdecl(p): p[0].entry.body = p[2] entry = p[0].entry - if entry.forwarded: - entry.forwarded = False + entry.forwarded = False def p_funcdeclforward(p): From bae55b2b2bf5bce2adaf34f947880bbae5db060f Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Thu, 5 Oct 2017 08:52:20 +0200 Subject: [PATCH 072/247] more test added --- tests/functional/dbbad.asm | 4 + tests/functional/dbbad.bin | Bin 0 -> 1 bytes tests/functional/read.asm | 1391 +++++++++++++ tests/functional/read.bas | 12 + tests/functional/read10.asm | 2820 ++++++++++++++++++++++++++ tests/functional/read10.bas | 21 + tests/functional/read12.asm | 2612 ++++++++++++++++++++++++ tests/functional/read12.bas | 14 + tests/functional/read4.asm | 1630 +++++++++++++++ tests/functional/read4.bas | 15 + tests/functional/read5.asm | 2784 ++++++++++++++++++++++++++ tests/functional/read5.bas | 18 + tests/functional/read6.bas | 18 + tests/functional/read7.bas | 17 + tests/functional/read8.asm | 2794 ++++++++++++++++++++++++++ tests/functional/read8.bas | 18 + tests/functional/read9.asm | 3013 ++++++++++++++++++++++++++++ tests/functional/read9.bas | 20 + tests/functional/readokdown.asm | 3277 +++++++++++++++++++++++++++++++ tests/functional/readokdown.bas | 43 + tests/functional/readokup.asm | 3276 ++++++++++++++++++++++++++++++ tests/functional/readokup.bas | 46 + 22 files changed, 23843 insertions(+) create mode 100644 tests/functional/dbbad.asm create mode 100644 tests/functional/dbbad.bin create mode 100644 tests/functional/read.asm create mode 100644 tests/functional/read.bas create mode 100644 tests/functional/read10.asm create mode 100644 tests/functional/read10.bas create mode 100644 tests/functional/read12.asm create mode 100644 tests/functional/read12.bas create mode 100644 tests/functional/read4.asm create mode 100644 tests/functional/read4.bas create mode 100644 tests/functional/read5.asm create mode 100644 tests/functional/read5.bas create mode 100644 tests/functional/read6.bas create mode 100644 tests/functional/read7.bas create mode 100644 tests/functional/read8.asm create mode 100644 tests/functional/read8.bas create mode 100644 tests/functional/read9.asm create mode 100644 tests/functional/read9.bas create mode 100644 tests/functional/readokdown.asm create mode 100644 tests/functional/readokdown.bas create mode 100644 tests/functional/readokup.asm create mode 100644 tests/functional/readokup.bas diff --git a/tests/functional/dbbad.asm b/tests/functional/dbbad.asm new file mode 100644 index 000000000..f65f5b5bb --- /dev/null +++ b/tests/functional/dbbad.asm @@ -0,0 +1,4 @@ + + +db 256 + diff --git a/tests/functional/dbbad.bin b/tests/functional/dbbad.bin new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/tests/functional/read.asm b/tests/functional/read.asm new file mode 100644 index 000000000..82d634059 --- /dev/null +++ b/tests/functional/read.asm @@ -0,0 +1,1391 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld hl, __DATA__0 + call __RESTORE + ld a, 9 + call __READ + ld hl, _a + call __STOREF +__LABEL__pera: +__LABEL__pina: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +___DATA__FUNCPTR__0: + ld hl, __LABEL0 + call __LOADSTR + jp ___DATA__FUNCPTR__0__leave +___DATA__FUNCPTR__0__leave: + ret +__DATA__0: + DEFB 3 + DEFB 20 + DEFB 3 + DEFB 20 + DEFB 3 + DEFB 30 +__DATA__1: + DEFB 81h + DEFW ___DATA__FUNCPTR__0 +__DATA__END: + DEFB 00h +__LABEL0: + DEFW 0004h + DEFB 4Ah + DEFB 75h + DEFB 61h + DEFB 6Eh +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 69 "alloc.asm" +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 70 "alloc.asm" + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 50 "read.bas" +#line 1 "read_restore.asm" + + ;; This implements READ & RESTORE functions + ;; Reads a new element from the DATA Address code + ;; Updates the DATA_ADDR read ptr for the next read + + ;; Data codification is 1 byte for type followed by data bytes + ;; Byte type is encoded as follows + +;; 00: End of data +;; 01: String +;; 02: Byte +;; 03: Ubyte +;; 04: Integer +;; 05: UInteger +;; 06: Long +;; 07: ULong +;; 08: Fixed +;; 09: Float + + ;; bit7 is set for a parameter-less function + ;; In that case, the next two bytes are the ptr of the function to jump + + + +#line 1 "iload32.asm" + + ; __FASTCALL__ routine which + ; loads a 32 bits integer into DE,HL + ; stored at position pointed by POINTER HL + ; DE,HL <-- (HL) + +__ILOAD32: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + ex de, hl + ret + +#line 25 "read_restore.asm" +#line 1 "iloadf.asm" + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- ((HL)) + +__ILOADF: + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- (HL) + +__LOADF: ; Loads a 40 bits FP number from address pointed by HL + ld a, (hl) + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld c, (hl) + inc hl + ld b, (hl) + ret + +#line 26 "read_restore.asm" +#line 1 "ftof16reg.asm" + +#line 1 "ftou32reg.asm" + +#line 1 "neg32.asm" + +__ABS32: + bit 7, d + ret z + +__NEG32: ; Negates DEHL (Two's complement) + ld a, l + cpl + ld l, a + + ld a, h + cpl + ld h, a + + ld a, e + cpl + ld e, a + + ld a, d + cpl + ld d, a + + inc l + ret nz + + inc h + ret nz + + inc de + ret + +#line 2 "ftou32reg.asm" + +__FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + ; Output: DEHL 32 bit number (signed) + PROC + + LOCAL __IS_FLOAT + + or a + jr nz, __IS_FLOAT + ; Here if it is a ZX ROM Integer + + ld h, c + ld l, d + ld a, e ; Takes sign: FF = -, 0 = + + ld de, 0 + inc a + jp z, __NEG32 ; Negates if negative + ret + +__IS_FLOAT: ; Jumps here if it is a true floating point number + ld h, e + push hl ; Stores it for later (Contains Sign in H) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + ;ld a, c ; Get exponent + sub 128 ; Exponent -= 128 + jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + +__FTOU32REG_LOOP: + exx ; Shift C'B' E'D' << 1, output bit stays in Carry + sla d + rl e + rl b + rl c + + exx ; Shift DEHL << 1, inserting the carry on the right + rl l + rl h + rl e + rl d + + djnz __FTOU32REG_LOOP + +__FTOU32REG_END: + pop af ; Take the sign bit + or a ; Sets SGN bit to 1 if negative + jp m, __NEG32 ; Negates DEHL + + ret + + ENDP + + +__FTOU8: ; Converts float in C ED LH to Unsigned byte in A + call __FTOU32REG + ld a, l + ret + +#line 2 "ftof16reg.asm" + +__FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + + ld l, a ; Saves exponent for later + or d + or e + or b + or c + ld h, e + ret z ; Return if ZERO + + push hl ; Stores it for later (Contains sign in H, exponent in L) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + pop bc + + ld a, c ; Get exponent + sub 112 ; Exponent -= 128 + 16 + + push bc ; Saves sign in b again + + jp z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jp c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + 16 (we need to shift 16 bit more) + jp __FTOU32REG_LOOP ; proceed as an u32 integer + +#line 27 "read_restore.asm" +#line 1 "f16tofreg.asm" + + +#line 1 "u32tofreg.asm" + + +__I8TOFREG: + ld l, a + rlca + sbc a, a ; A = SGN(A) + ld h, a + ld e, a + ld d, a + +__I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) + ; to a Floating Point Number returned in (A ED CB) + + ld a, d + or a ; Test sign + + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __U32TOFREG ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + +__U8TOFREG: + ; Converts an unsigned 8 bit (A) to Floating point + ld l, a + ld h, 0 + ld e, h + ld d, h + +__U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in A ED CB + + PROC + + LOCAL __U32TOFREG_END + + ld a, d + or e + or h + or l + ld b, d + ld c, e ; Returns 00 0000 0000 if ZERO + ret z + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 128 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + +__U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG + exx + ld a, d ; B'C'D'E' == 0 ? + or e + or b + or c + jp z, __U32TOFREG_END ; We are done + + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry + rr c + rr d + rr e + exx + + rr e ; Shift EDCB >> 1, inserting the carry on the left + rr d + rr c + rr b + + inc l ; Increment exponent + jp __U32TOFREG_LOOP + + +__U32TOFREG_END: + exx + ld a, l ; Puts the exponent in a + res 7, e ; Sets the sign bit to 0 (positive) + + ret + ENDP + +#line 3 "f16tofreg.asm" + +__F16TOFREG: ; Converts a 16.16 signed fixed point (stored in DEHL) + ; to a Floating Point Number returned in (C ED CB) + PROC + + LOCAL __F16TOFREG2 + + ld a, d + or a ; Test sign + + jp p, __F16TOFREG2 ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __F16TOFREG2 ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + + +__F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in C DE HL + + ld a, d + or e + or h + or l + ld b, h + ld c, l + ret z ; Return 00 0000 0000 if 0 + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 112 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + jp __U32TOFREG_LOOP ; Proceed as an integer + + ENDP + +#line 28 "read_restore.asm" +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 29 "read_restore.asm" + + + + + + + + + + + + + ;; Updates restore point to the given HL mem. address +__RESTORE: + PROC + LOCAL __DATA_ADDR + + ld (__DATA_ADDR), hl + ret + + ;; Reads a value from the DATA mem area and updates __DATA_ADDR ptr to the + ;; next item. On Out Of Data, restarts + ;; +__READ: + LOCAL read_restart, cont, cont2, table, no_func + LOCAL dynamic_cast, dynamic_cast2, dynamic_cast3, dynamic_cast4 + LOCAL _decode_table, coerce_to_int, coerce_to_int2, promote_to_i16 + LOCAL _from_i8, _from_u8 + LOCAL _from_i16, _from_u16 + LOCAL _from_i32, _from_u32 + LOCAL _from_fixed, __data_error + + push af ; type of data to read + ld hl, (__DATA_ADDR) +read_restart: + ld a, (hl) + or a ; 0 => OUT of data + jr nz, cont + ;; Signals out of data + + ld hl, __DATA__0 + ld (__DATA_ADDR), hl + jr read_restart ; Start again +cont: + and 0x80 + ld a, (hl) + push af + jp z, no_func ;; Loads data directly, not a function + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl +cont2: + ld de, dynamic_cast + push de ; ret address + jp (hl) ; "call (hl)" + + ;; Now tries to convert the given result to the expected type or raise an error +dynamic_cast: + exx + ex af, af' + pop af ; type READ + and 0x7F ; clear bit 7 + pop hl ; type requested by USER (type of the READ variable) + ld c, h ; save requested type (save it in register C) + cp h + exx + jr nz, dynamic_cast2 ; Types are identical? + ;; yes, they are + ex af, af' + ret + +dynamic_cast2: + cp 1 ; Requested a number, but read a string? + jr nz, dynamic_cast3 + call __MEM_FREE ; Frees str from memory + jr __data_error + +dynamic_cast3: + exx + ld b, a ; Read type + ld a, c ; Requested type + cp 1 + jr z, __data_error + cp b + jr c, dynamic_cast4 + ;; here the user expected type is "larger" than the read one + ld a, b + sub 2 + add a, a + ld l, a + ld h, 0 + ld de, _decode_table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl + ld a, c ; Requested type + exx + ret + +__data_error: + ;; When a data is read, but cannot be converted to the requested type + ;; that is, the user asked for a string and we read a number or vice versa + ld a, ERROR_InvalidArg + call __STOP ; The user expected a string, but read a number + xor a + ld h, a + ld l, a + ld e, a + ld d, a + ld b, a + ld c, a + ret + +_decode_table: + dw _from_i8 + dw _from_u8 + dw _from_i16 + dw _from_u16 + dw _from_i32 + dw _from_u32 + dw _from_fixed + +_from_i8: + cp 4 + jr nc, promote_to_i16 + ex af, af' + ret ;; Was from Byte to Ubyte + +promote_to_i16: + ex af, af' + ld l, a + rla + sbc a, a + ld h, a ; copy sgn to h + ex af, af' + jr _before_from_i16 + +_from_u8: + ex af, af' + ld l, a + ld h, 0 + ex af, af' + ;; Promoted to i16 + +_before_from_i16: +_from_i16: + cp 6 + ret c ;; from i16 to u16 + ;; Promote i16 to i32 + ex af, af' + ld a, h + rla + sbc a, a + ld e, a + ld d, a + ex af, af' +_from_i32: + cp 7 + ret z ;; From i32 to u32 + ret c ;; From u16 to i32 + cp 9 + jp z, __I32TOFREG +_from_u32: + cp 9 + jp z, __U32TOFREG + ex de, hl + ld hl, 0 + cp 8 + ret z +_from_fixed: ;; From fixed to float + jp __F16TOFREG +_from_u16: + ld de, 0 ; HL 0x0000 => 32 bits + jp _from_i32 + +dynamic_cast4: + ;; The user type is "shorter" than the read one + cp 8 ;; required type + jr c, before_to_int ;; required < fixed (f16) + ex af, af' + exx ;; Ok, we must convert from float to f16 + jp __FTOF16REG + +before_to_int: + ld a, b ;; read type + cp 8 ;; + jr nz, coerce_to_int ;; From float to int + ld a, c ;; user type + exx + ;; f16 to Long + ex de, hl + ld a, h + rla + sbc a, a + ld d, a + ld e, a + exx + jr coerce_to_int2 +coerce_to_int: + exx + ex af, af' + call __FTOU32REG + ex af, af' ; a contains user type + exx +coerce_to_int2: ; At this point we have an u/integer in hl + exx + cp 4 + ret nc ; Already done. Return the result + ld a, l ; Truncate to byte + ret + +no_func: + exx + ld de, dynamic_cast + push de ; Ret address + dec a ; 0 => string; 1, 2 => byte; 3, 4 => integer; 5, 6 => long, 7 => fixed; 8 => float + ld h, 0 + add a, a + ld l, a + ld de, table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl ; address to jump to + exx + inc hl + ret ; jp (sp) => jump to table[a - 1] + +table: + LOCAL __01_decode_string + LOCAL __02_decode_byte + LOCAL __03_decode_ubyte + LOCAL __04_decode_integer + LOCAL __05_decode_uinteger + LOCAL __06_decode_long + LOCAL __07_decode_ulong + LOCAL __08_decode_fixed + LOCAL __09_decode_float + + ;; 1 -> Decode string + ;; 2, 3 -> Decode Byte, UByte + ;; 4, 5 -> Decode Integer, UInteger + ;; 6, 7 -> Decode Long, ULong + ;; 8 -> Decode Fixed + ;; 9 -> Decode Float + dw __01_decode_string + dw __02_decode_byte + dw __03_decode_ubyte + dw __04_decode_integer + dw __05_decode_uinteger + dw __06_decode_long + dw __07_decode_ulong + dw __08_decode_fixed + dw __09_decode_float + +__01_decode_string: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl + jp __LOADSTR + +__02_decode_byte: +__03_decode_ubyte: + ld a, (hl) + inc hl + ld (__DATA_ADDR), hl + ret + +__04_decode_integer: +__05_decode_uinteger: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl + ex de, hl + ret + +__06_decode_long: +__07_decode_ulong: +__08_decode_fixed: + ld b, h + ld c, l + inc bc + inc bc + inc bc + inc bc + ld (__DATA_ADDR), bc + jp __ILOAD32 + +__09_decode_float: + call __LOADF + inc hl + ld (__DATA_ADDR), hl + ld h, a ; returns A in H; sets A free + ret + +__DATA_ADDR: ;; Stores current DATA ptr + dw __DATA__0 + ENDP + + + + + + + + + + +#line 51 "read.bas" +#line 1 "storef.asm" + +__PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) + push de + ex de, hl ; DE <- HL + push ix + pop hl ; HL <- IX + add hl, de ; HL <- IX + HL + pop de + +__ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register + ex af, af' + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex af, af' + +__STOREF: ; Stores the given FP number in A EDCB at address HL + ld (hl), a + inc hl + ld (hl), e + inc hl + ld (hl), d + inc hl + ld (hl), c + inc hl + ld (hl), b + ret + +#line 52 "read.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 00, 00, 00, 00, 00 +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/read.bas b/tests/functional/read.bas new file mode 100644 index 000000000..7c98cddd4 --- /dev/null +++ b/tests/functional/read.bas @@ -0,0 +1,12 @@ + + +RESTORE pera + +READ a + +pera: +DATA 10 * 2, 20, 30 + +pina: +DATA "Juan" + diff --git a/tests/functional/read10.asm b/tests/functional/read10.asm new file mode 100644 index 000000000..e88be16e6 --- /dev/null +++ b/tests/functional/read10.asm @@ -0,0 +1,2820 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + call __PRINT_INIT + ld hl, __DATA__0 + call __RESTORE + call _p + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +_p: + push ix + ld ix, 0 + add ix, sp + ld hl, 0 + push hl + push hl + push hl + ld (ix-1), 0 + jp __LABEL0 +__LABEL3: + ld a, 9 + call __READ + ld hl, -6 + call __PSTOREF + push ix + pop hl + ld de, -6 + add hl, de + call __PLOADF + call __PRINTF + call PRINT_EOL +__LABEL4: + ld a, (ix-1) + inc a + ld (ix-1), a +__LABEL0: + ld a, (ix-1) + push af + ld a, 3 + pop hl + cp h + jp nc, __LABEL3 +__LABEL2: +_p__leave: + ld sp, ix + pop ix + ret +___DATA__FUNCPTR__0: + ld a, (_v) + ld de, (_v + 1) + ld bc, (_v + 3) + ld hl, 00000h + push hl + ld hl, 00048h + push hl + ld h, 085h + push hl + call __MULF + jp ___DATA__FUNCPTR__0__leave +___DATA__FUNCPTR__0__leave: + ret +___DATA__FUNCPTR__1: + ld a, (_v) + ld de, (_v + 1) + ld bc, (_v + 3) + call SIN + push bc + push de + push af + ld a, (_v) + ld de, (_v + 1) + ld bc, (_v + 3) + call TAN + push bc + push de + push af + ld a, 082h + ld de, 00000h + ld bc, 00000h + call __POW + call __MULF + jp ___DATA__FUNCPTR__1__leave +___DATA__FUNCPTR__1__leave: + ret +___DATA__FUNCPTR__2: + ld a, (_v) + ld de, (_v + 1) + ld bc, (_v + 3) + ld hl, 0A2DAh + push hl + ld hl, 00F49h + push hl + ld h, 082h + push hl + call __MULF + jp ___DATA__FUNCPTR__2__leave +___DATA__FUNCPTR__2__leave: + ret +__DATA__0: + DEFB 3 + DEFB 10 + DEFB 89h + DEFW ___DATA__FUNCPTR__0 + DEFB 89h + DEFW ___DATA__FUNCPTR__1 + DEFB 89h + DEFW ___DATA__FUNCPTR__2 +__DATA__END: + DEFB 00h +#line 1 "mulf.asm" + +#line 1 "stackf.asm" + + ; ------------------------------------------------------------- + ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC + ; ------------------------------------------------------------- + + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) + __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) + +__FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) + ; Second argument to push into the stack calculator is popped out of the stack + ; Since the caller routine also receives the parameters into the top of the stack + ; four bytes must be removed from SP before pop them out + + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK + exx + pop hl ; Caller-Caller return addr + exx + pop hl ; Caller return addr + + pop af + pop de + pop bc + + push hl ; Caller return addr + exx + push hl ; Caller-Caller return addr + exx + + jp __FPSTACK_PUSH + + +__FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK + ; This format is specified in the ZX 48K Manual + ; You can push a 16 bit signed integer as + ; 0 SS LL HH 0, being SS the sign and LL HH the low + ; and High byte respectively + ld a, h + rla ; sign to Carry + sbc a, a ; 0 if positive, FF if negative + ld e, a + ld d, l + ld c, h + xor a + ld b, a + jp __FPSTACK_PUSH +#line 2 "mulf.asm" + + ; ------------------------------------------------------------- + ; Floating point library using the FP ROM Calculator (ZX 48K) + ; All of them uses A EDCB registers as 1st paramter. + ; For binary operators, the 2n operator must be pushed into the + ; stack, in the order A DE BC. + ; + ; Uses CALLEE convention + ; ------------------------------------------------------------- + +__MULF: ; Multiplication + call __FPSTACK_PUSH2 + + ; ------------- ROM MUL + rst 28h + defb 04h ; + defb 38h; ; END CALC + + jp __FPSTACK_POP + +#line 121 "read10.bas" +#line 1 "ploadf.asm" + + ; Parameter / Local var load + ; A => Offset + ; IX = Stack Frame +; RESULT: HL => IX + DE + +#line 1 "iloadf.asm" + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- ((HL)) + +__ILOADF: + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- (HL) + +__LOADF: ; Loads a 40 bits FP number from address pointed by HL + ld a, (hl) + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld c, (hl) + inc hl + ld b, (hl) + ret + +#line 7 "ploadf.asm" + +__PLOADF: + push ix + pop hl + add hl, de + jp __LOADF + +#line 122 "read10.bas" +#line 1 "pow.asm" + + + + ; ------------------------------------------------------------- + ; Floating point library using the FP ROM Calculator (ZX 48K) + + ; All of them uses A EDCB registers as 1st paramter. + ; For binary operators, the 2n operator must be pushed into the + ; stack, in the order A DE BC. + ; + ; Uses CALLEE convention + ; +; Operands comes swapped: + ; 1 st parameter is the BASE (A ED CB) + ; 2 nd parameter (Top of the stack) is Exponent + ; ------------------------------------------------------------- + +__POW: ; Exponentiation + PROC + + call __FPSTACK_PUSH2 + + ; ------------- ROM POW + rst 28h + defb 01h ; Exchange => 1, Base + defb 06h ; POW + defb 38h; ; END CALC + + jp __FPSTACK_POP + + ENDP + +#line 123 "read10.bas" +#line 1 "print.asm" + +; vim:ts=4:sw=4:et: + ; PRINT command routine + ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that + +#line 1 "sposn.asm" + + ; Printing positioning library. + PROC + LOCAL ECHO_E + +__LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. + ld de, (S_POSN) + ld hl, (MAXX) + or a + sbc hl, de + ex de, hl + ret + + +__SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. + ld hl, (MAXX) + or a + sbc hl, de + ld (S_POSN), hl ; saves it again + ret + + + ECHO_E EQU 23682 + MAXX EQU ECHO_E ; Max X position + 1 + MAXY EQU MAXX + 1 ; Max Y position + 1 + + S_POSN EQU 23688 + POSX EQU S_POSN ; Current POS X + POSY EQU S_POSN + 1 ; Current POS Y + + ENDP + +#line 6 "print.asm" +#line 1 "cls.asm" + + ; JUMPS directly to spectrum CLS + ; This routine does not clear lower screen + + ;CLS EQU 0DAFh + + ; Our faster implementation + + + +CLS: + PROC + + LOCAL COORDS + LOCAL __CLS_SCR + LOCAL ATTR_P + LOCAL SCREEN + + ld hl, 0 + ld (COORDS), hl + ld hl, 1821h + ld (S_POSN), hl +__CLS_SCR: + ld hl, SCREEN + ld (hl), 0 + ld d, h + ld e, l + inc de + ld bc, 6144 + ldir + + ; Now clear attributes + + ld a, (ATTR_P) + ld (hl), a + ld bc, 767 + ldir + ret + + COORDS EQU 23677 + SCREEN EQU 16384 ; Default start of the screen (can be changed) + ATTR_P EQU 23693 + ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address + + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines + ; to get the start of the screen + ENDP + +#line 7 "print.asm" +#line 1 "in_screen.asm" + + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 3 "in_screen.asm" + +__IN_SCREEN: + ; Returns NO carry if current coords (D, E) + ; are OUT of the screen limits (MAXX, MAXY) + + PROC + LOCAL __IN_SCREEN_ERR + + ld hl, MAXX + ld a, e + cp (hl) + jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + + ld a, d + inc hl + cp (hl) + ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + ;; ret + ret c ; Return if carry (OK) + +__IN_SCREEN_ERR: +__OUT_OF_SCREEN_ERR: + ; Jumps here if out of screen + ld a, ERROR_OutOfScreen + jp __STOP ; Saves error code and exits + + ENDP +#line 8 "print.asm" +#line 1 "table_jump.asm" + + +JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A + add a, a + +JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE + ld e, a + ld d, 0 + +JUMP_HL_PLUS_DE: ; Does JP (HL + DE) + add hl, de + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl +CALL_HL: + jp (hl) + +#line 9 "print.asm" +#line 1 "ink.asm" + + ; Sets ink color in ATTR_P permanently +; Parameter: Paper color in A register + +#line 1 "const.asm" + + ; Global constants + + P_FLAG EQU 23697 + FLAGS2 EQU 23681 + ATTR_P EQU 23693 ; permanet ATTRIBUTES + ATTR_T EQU 23695 ; temporary ATTRIBUTES + CHARS EQU 23606 ; Pointer to ROM/RAM Charset + UDG EQU 23675 ; Pointer to UDG Charset + MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars + +#line 5 "ink.asm" + +INK: + PROC + LOCAL __SET_INK + LOCAL __SET_INK2 + + ld de, ATTR_P + +__SET_INK: + cp 8 + jr nz, __SET_INK2 + + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + or 7 ; Set bits 0,1,2 to enable transparency + ld (de), a + ret + +__SET_INK2: + ; Another entry. This will set the ink color at location pointer by DE + and 7 ; # Gets color mod 8 + ld b, a ; Saves the color + ld a, (de) + and 0F8h ; Clears previous value + or b + ld (de), a + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + and 0F8h ; Reset bits 0,1,2 sign to disable transparency + ld (de), a ; Store new attr + ret + + ; Sets the INK color passed in A register in the ATTR_T variable +INK_TMP: + ld de, ATTR_T + jp __SET_INK + + ENDP + +#line 10 "print.asm" +#line 1 "paper.asm" + + ; Sets paper color in ATTR_P permanently +; Parameter: Paper color in A register + + + +PAPER: + PROC + LOCAL __SET_PAPER + LOCAL __SET_PAPER2 + + ld de, ATTR_P + +__SET_PAPER: + cp 8 + jr nz, __SET_PAPER2 + inc de + ld a, (de) + or 038h + ld (de), a + ret + + ; Another entry. This will set the paper color at location pointer by DE +__SET_PAPER2: + and 7 ; # Remove + rlca + rlca + rlca ; a *= 8 + + ld b, a ; Saves the color + ld a, (de) + and 0C7h ; Clears previous value + or b + ld (de), a + inc de ; Points to MASK_T or MASK_P accordingly + ld a, (de) + and 0C7h ; Resets bits 3,4,5 + ld (de), a + ret + + + ; Sets the PAPER color passed in A register in the ATTR_T variable +PAPER_TMP: + ld de, ATTR_T + jp __SET_PAPER + ENDP + +#line 11 "print.asm" +#line 1 "flash.asm" + + ; Sets flash flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +FLASH: + ld de, ATTR_P +__SET_FLASH: + ; Another entry. This will set the flash flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + ld b, a ; Saves the color + ld a, (de) + and 07Fh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the FLASH flag passed in A register in the ATTR_T variable +FLASH_TMP: + ld de, ATTR_T + jr __SET_FLASH + +#line 12 "print.asm" +#line 1 "bright.asm" + + ; Sets bright flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +BRIGHT: + ld de, ATTR_P + +__SET_BRIGHT: + ; Another entry. This will set the bright flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + rrca + ld b, a ; Saves the color + ld a, (de) + and 0BFh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable +BRIGHT_TMP: + ld de, ATTR_T + jr __SET_BRIGHT + +#line 13 "print.asm" +#line 1 "over.asm" + + ; Sets OVER flag in P_FLAG permanently +; Parameter: OVER flag in bit 0 of A register +#line 1 "copy_attr.asm" + + + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" + + + +COPY_ATTR: + ; Just copies current permanent attribs to temporal attribs + ; and sets print mode + PROC + + LOCAL INVERSE1 + LOCAL __REFRESH_TMP + + INVERSE1 EQU 02Fh + + ld hl, (ATTR_P) + ld (ATTR_T), hl + + ld hl, FLAGS2 + call __REFRESH_TMP + + ld hl, P_FLAG + call __REFRESH_TMP + + +__SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) + + + LOCAL TABLE + LOCAL CONT2 + + rra ; Over bit to carry + ld a, (FLAGS2) + rla ; Over bit in bit 1, Over2 bit in bit 2 + and 3 ; Only bit 0 and 1 (OVER flag) + + ld c, a + ld b, 0 + + ld hl, TABLE + add hl, bc + ld a, (hl) + ld (PRINT_MODE), a + + ld hl, (P_FLAG) + xor a ; NOP -> INVERSE0 + bit 2, l + jr z, CONT2 + ld a, INVERSE1 ; CPL -> INVERSE1 + +CONT2: + ld (INVERSE_MODE), a + ret + +TABLE: + nop ; NORMAL MODE + xor (hl) ; OVER 1 MODE + and (hl) ; OVER 2 MODE + or (hl) ; OVER 3 MODE + +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" + +__REFRESH_TMP: + ld a, (hl) + and 10101010b + ld c, a + rra + or c + ld (hl), a + ret + + ENDP + +#line 4 "over.asm" + + +OVER: + PROC + + ld c, a ; saves it for later + and 2 + ld hl, FLAGS2 + res 1, (HL) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 ; # Convert to 0/1 + add a, a; # Shift left 1 bit for permanent + + ld hl, P_FLAG + res 1, (hl) + or (hl) + ld (hl), a + ret + + ; Sets OVER flag in P_FLAG temporarily +OVER_TMP: + ld c, a ; saves it for later + and 2 ; gets bit 1; clears carry + rra + ld hl, FLAGS2 + res 0, (hl) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 + ld hl, P_FLAG + res 0, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 14 "print.asm" +#line 1 "inverse.asm" + + ; Sets INVERSE flag in P_FLAG permanently +; Parameter: INVERSE flag in bit 0 of A register + + + +INVERSE: + PROC + + and 1 ; # Convert to 0/1 + add a, a; # Shift left 3 bits for permanent + add a, a + add a, a + ld hl, P_FLAG + res 3, (hl) + or (hl) + ld (hl), a + ret + + ; Sets INVERSE flag in P_FLAG temporarily +INVERSE_TMP: + and 1 + add a, a + add a, a; # Shift left 2 bits for temporary + ld hl, P_FLAG + res 2, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 15 "print.asm" +#line 1 "bold.asm" + + ; Sets BOLD flag in P_FLAG permanently +; Parameter: BOLD flag in bit 0 of A register + + +BOLD: + PROC + + and 1 + rlca + rlca + rlca + ld hl, FLAGS2 + res 3, (HL) + or (hl) + ld (hl), a + ret + + ; Sets BOLD flag in P_FLAG temporarily +BOLD_TMP: + and 1 + rlca + rlca + ld hl, FLAGS2 + res 2, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 16 "print.asm" +#line 1 "italic.asm" + + ; Sets ITALIC flag in P_FLAG permanently +; Parameter: ITALIC flag in bit 0 of A register + + +ITALIC: + PROC + + and 1 + rrca + rrca + rrca + ld hl, FLAGS2 + res 5, (HL) + or (hl) + ld (hl), a + ret + + ; Sets ITALIC flag in P_FLAG temporarily +ITALIC_TMP: + and 1 + rrca + rrca + rrca + rrca + ld hl, FLAGS2 + res 4, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 17 "print.asm" + +#line 1 "attr.asm" + + ; Attribute routines +; vim:ts=4:et:sw: + + + + + + + +__ATTR_ADDR: + ; calc start address in DE (as (32 * d) + e) + ; Contributed by Santiago Romero at http://www.speccy.org + ld h, 0 ; 7 T-States + ld a, d ; 4 T-States + add a, a ; a * 2 ; 4 T-States + add a, a ; a * 4 ; 4 T-States + ld l, a ; HL = A * 4 ; 4 T-States + + add hl, hl ; HL = A * 8 ; 15 T-States + add hl, hl ; HL = A * 16 ; 15 T-States + add hl, hl ; HL = A * 32 ; 15 T-States + + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) + add hl, de + + ld de, (SCREEN_ADDR) ; Adds the screen address + add hl, de + + ; Return current screen address in HL + ret + + + ; Sets the attribute at a given screen coordinate (D, E). + ; The attribute is taken from the ATTR_T memory variable + ; Used by PRINT routines +SET_ATTR: + + ; Checks for valid coords + call __IN_SCREEN + ret nc + +__SET_ATTR: + ; Internal __FASTCALL__ Entry used by printing routines + PROC + + call __ATTR_ADDR + ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T + + ld a, d + and (hl) + ld c, a ; C = current screen color, masked + + ld a, d + cpl ; Negate mask + and e ; Mask current attributes + or c ; Mix them + ld (hl), a ; Store result in screen + + ret + + ENDP + + +#line 19 "print.asm" + + ; Putting a comment starting with @INIT
+ ; will make the compiler to add a CALL to
+ ; It is useful for initialization routines. + + +__PRINT_INIT: ; To be called before program starts (initializes library) + PROC + + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + + ld hl, 1821h + ld (MAXX), hl ; Sets current maxX and maxY + + xor a + ld (FLAGS2), a + + ret + + +__PRINTCHAR: ; Print character store in accumulator (A register) + ; Modifies H'L', B'C', A'F', D'E', A + + LOCAL PO_GR_1 + + LOCAL __PRCHAR + LOCAL __PRINT_CONT + LOCAL __PRINT_CONT2 + LOCAL __PRINT_JUMP + LOCAL __SRCADDR + LOCAL __PRINT_UDG + LOCAL __PRGRAPH + LOCAL __PRINT_START + + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 + +__PRINT_JUMP: + jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively + +__PRINT_START: + cp ' ' + jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones + + exx ; Switch to alternative registers + ex af, af' ; Saves a value (char to print) for later + + call __LOAD_S_POSN + + ; At this point we have the new coord + ld hl, (SCREEN_ADDR) + + ld a, d + ld c, a ; Saves it for later + + and 0F8h ; Masks 3 lower bit ; zy + ld d, a + + ld a, c ; Recovers it + and 07h ; MOD 7 ; y1 + rrca + rrca + rrca + + or e + ld e, a + add hl, de ; HL = Screen address + DE + ex de, hl ; DE = Screen address + + ex af, af' + + cp 80h ; Is it an UDG or a ? + jp c, __SRCADDR + + cp 90h + jp nc, __PRINT_UDG + + ; Print a 8 bit pattern (80h to 8Fh) + + ld b, a + call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 + ld hl, MEM0 + jp __PRGRAPH + + PO_GR_1 EQU 0B38h + +__PRINT_UDG: + sub 90h ; Sub ASC code + ld bc, (UDG) + jp __PRGRAPH0 + + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source +__SRCADDR: + ld bc, (CHARS) + +__PRGRAPH0: + add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org + ld l, a + ld h, 0 ; HL = a * 2 (accumulator) + add hl, hl + add hl, hl ; HL = a * 8 + add hl, bc ; HL = CHARS address + +__PRGRAPH: + ex de, hl ; HL = Write Address, DE = CHARS address + bit 2, (iy + $47) + call nz, __BOLD + bit 4, (iy + $47) + call nz, __ITALIC + ld b, 8 ; 8 bytes per char +__PRCHAR: + ld a, (de) ; DE *must* be ALWAYS source, and HL destiny + +PRINT_MODE: ; Which operation is used to write on the screen + ; Set it with: + ; LD A, + ; LD (PRINT_MODE), A + ; + ; Available opertions: + ; NORMAL: 0h --> NOP ; OVER 0 + ; XOR : AEh --> XOR (HL) ; OVER 1 + ; OR : B6h --> OR (HL) ; PUTSPRITE + ; AND : A6h --> AND (HL) ; PUTMASK + nop ; + +INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 + nop ; 2F -> CPL -> INVERSE 1 + + ld (hl), a + + inc de + inc h ; Next line + djnz __PRCHAR + + call __LOAD_S_POSN + push de + call __SET_ATTR + pop de + inc e ; COL = COL + 1 + ld hl, (MAXX) + ld a, e + dec l ; l = MAXX + cp l ; Lower than max? + jp c, __PRINT_CONT; Nothing to do + call __PRINT_EOL1 + exx ; counteracts __PRINT_EOL1 exx + jp __PRINT_CONT2 + +__PRINT_CONT: + call __SAVE_S_POSN + +__PRINT_CONT2: + exx + ret + + ; ------------- SPECIAL CHARS (< 32) ----------------- + +__PRINT_SPECIAL: ; Jumps here if it is a special char + exx + ld hl, __PRINT_TABLE + jp JUMP_HL_PLUS_2A + + +PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence + exx + +__PRINT_0Dh: ; Called WHEN printing CHR$(13) + call __LOAD_S_POSN + +__PRINT_EOL1: ; Another entry called from PRINT when next line required + ld e, 0 + +__PRINT_EOL2: + ld a, d + inc a + +__PRINT_AT1_END: + ld hl, (MAXY) + cp l + jr c, __PRINT_EOL_END ; Carry if (MAXY) < d + xor a + +__PRINT_EOL_END: + ld d, a + +__PRINT_AT2_END: + call __SAVE_S_POSN + exx + ret + +__PRINT_COM: + exx + push hl + push de + push bc + call PRINT_COMMA + pop bc + pop de + pop hl + ret + +__PRINT_TAB: + ld hl, __PRINT_TAB1 + jp __PRINT_SET_STATE + +__PRINT_TAB1: + ld (MEM0), a + ld hl, __PRINT_TAB2 + ld (PRINT_JUMP_STATE), hl + ret + +__PRINT_TAB2: + ld a, (MEM0) ; Load tab code (ignore the current one) + push hl + push de + push bc + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + call PRINT_TAB + pop bc + pop de + pop hl + ret + +__PRINT_NOP: +__PRINT_RESTART: + ld hl, __PRINT_START + jp __PRINT_SET_STATE + +__PRINT_AT: + ld hl, __PRINT_AT1 + +__PRINT_SET_STATE: + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + exx + ret + +__PRINT_AT1: ; Jumps here if waiting for 1st parameter + exx + ld hl, __PRINT_AT2 + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + jp __PRINT_AT1_END + +__PRINT_AT2: + exx + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + ld e, a + ld hl, (MAXX) + cp (hl) + jr c, __PRINT_AT2_END + jr __PRINT_EOL1 + +__PRINT_DEL: + call __LOAD_S_POSN ; Gets current screen position + dec e + ld a, -1 + cp e + jp nz, __PRINT_AT2_END + ld hl, (MAXX) + ld e, l + dec e + dec e + dec d + cp d + jp nz, __PRINT_AT2_END + ld d, h + dec d + jp __PRINT_AT2_END + +__PRINT_INK: + ld hl, __PRINT_INK2 + jp __PRINT_SET_STATE + +__PRINT_INK2: + exx + call INK_TMP + jp __PRINT_RESTART + +__PRINT_PAP: + ld hl, __PRINT_PAP2 + jp __PRINT_SET_STATE + +__PRINT_PAP2: + exx + call PAPER_TMP + jp __PRINT_RESTART + +__PRINT_FLA: + ld hl, __PRINT_FLA2 + jp __PRINT_SET_STATE + +__PRINT_FLA2: + exx + call FLASH_TMP + jp __PRINT_RESTART + +__PRINT_BRI: + ld hl, __PRINT_BRI2 + jp __PRINT_SET_STATE + +__PRINT_BRI2: + exx + call BRIGHT_TMP + jp __PRINT_RESTART + +__PRINT_INV: + ld hl, __PRINT_INV2 + jp __PRINT_SET_STATE + +__PRINT_INV2: + exx + call INVERSE_TMP + jp __PRINT_RESTART + +__PRINT_OVR: + ld hl, __PRINT_OVR2 + jp __PRINT_SET_STATE + +__PRINT_OVR2: + exx + call OVER_TMP + jp __PRINT_RESTART + +__PRINT_BOLD: + ld hl, __PRINT_BOLD2 + jp __PRINT_SET_STATE + +__PRINT_BOLD2: + exx + call BOLD_TMP + jp __PRINT_RESTART + +__PRINT_ITA: + ld hl, __PRINT_ITA2 + jp __PRINT_SET_STATE + +__PRINT_ITA2: + exx + call ITALIC_TMP + jp __PRINT_RESTART + + +__BOLD: + push hl + ld hl, MEM0 + ld b, 8 +__BOLD_LOOP: + ld a, (de) + ld c, a + rlca + or c + ld (hl), a + inc hl + inc de + djnz __BOLD_LOOP + pop hl + ld de, MEM0 + ret + + +__ITALIC: + push hl + ld hl, MEM0 + ex de, hl + ld bc, 8 + ldir + ld hl, MEM0 + srl (hl) + inc hl + srl (hl) + inc hl + srl (hl) + inc hl + inc hl + inc hl + sla (hl) + inc hl + sla (hl) + inc hl + sla (hl) + pop hl + ld de, MEM0 + ret + +PRINT_COMMA: + call __LOAD_S_POSN + ld a, e + and 16 + add a, 16 + +PRINT_TAB: + PROC + LOCAL LOOP, CONTINUE + + inc a + call __LOAD_S_POSN ; e = current row + ld d, a + ld a, e + cp 21h + jr nz, CONTINUE + ld e, -1 +CONTINUE: + ld a, d + inc e + sub e ; A = A - E + and 31 ; + ret z ; Already at position E + ld b, a +LOOP: + ld a, ' ' + call __PRINTCHAR + djnz LOOP + ret + ENDP + +PRINT_AT: ; CHanges cursor to ROW, COL + ; COL in A register + ; ROW in stack + + pop hl ; Ret address + ex (sp), hl ; callee H = ROW + ld l, a + ex de, hl + + call __IN_SCREEN + ret nc ; Return if out of screen + + jp __SAVE_S_POSN + + LOCAL __PRINT_COM + LOCAL __BOLD + LOCAL __BOLD_LOOP + LOCAL __ITALIC + LOCAL __PRINT_EOL1 + LOCAL __PRINT_EOL2 + LOCAL __PRINT_AT1 + LOCAL __PRINT_AT2 + LOCAL __PRINT_AT2_END + LOCAL __PRINT_BOLD + LOCAL __PRINT_BOLD2 + LOCAL __PRINT_ITA + LOCAL __PRINT_ITA2 + LOCAL __PRINT_INK + LOCAL __PRINT_PAP + LOCAL __PRINT_SET_STATE + LOCAL __PRINT_TABLE + LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 + +__PRINT_TABLE: ; Jump table for 0 .. 22 codes + + DW __PRINT_NOP ; 0 + DW __PRINT_NOP ; 1 + DW __PRINT_NOP ; 2 + DW __PRINT_NOP ; 3 + DW __PRINT_NOP ; 4 + DW __PRINT_NOP ; 5 + DW __PRINT_COM ; 6 COMMA + DW __PRINT_NOP ; 7 + DW __PRINT_DEL ; 8 DEL + DW __PRINT_NOP ; 9 + DW __PRINT_NOP ; 10 + DW __PRINT_NOP ; 11 + DW __PRINT_NOP ; 12 + DW __PRINT_0Dh ; 13 + DW __PRINT_BOLD ; 14 + DW __PRINT_ITA ; 15 + DW __PRINT_INK ; 16 + DW __PRINT_PAP ; 17 + DW __PRINT_FLA ; 18 + DW __PRINT_BRI ; 19 + DW __PRINT_INV ; 20 + DW __PRINT_OVR ; 21 + DW __PRINT_AT ; 22 AT + DW __PRINT_TAB ; 23 TAB + + ENDP + + +#line 124 "read10.bas" +#line 1 "printf.asm" + +#line 1 "printstr.asm" + + + + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 5 "printstr.asm" + + ; PRINT command routine + ; Prints string pointed by HL + +PRINT_STR: +__PRINTSTR: ; __FASTCALL__ Entry to print_string + PROC + LOCAL __PRINT_STR_LOOP + LOCAL __PRINT_STR_END + + ld d, a ; Saves A reg (Flag) for later + + ld a, h + or l + ret z ; Return if the pointer is NULL + + push hl + + ld c, (hl) + inc hl + ld b, (hl) + inc hl ; BC = LEN(a$); HL = &a$ + +__PRINT_STR_LOOP: + ld a, b + or c + jr z, __PRINT_STR_END ; END if BC (counter = 0) + + ld a, (hl) + call __PRINTCHAR + inc hl + dec bc + jp __PRINT_STR_LOOP + +__PRINT_STR_END: + pop hl + ld a, d ; Recovers A flag + or a ; If not 0 this is a temporary string. Free it + ret z + jp __MEM_FREE ; Frees str from heap and return from there + +__PRINT_STR: + ; Fastcall Entry + ; It ONLY prints strings + ; HL = String start + ; BC = String length (Number of chars) + push hl ; Push str address for later + ld d, a ; Saves a FLAG + jp __PRINT_STR_LOOP + + ENDP + +#line 2 "printf.asm" + + + +__PRINTF: ; Prints a Fixed point Number stored in C ED LH + PROC + + LOCAL RECLAIM2 + LOCAL STK_END + STK_END EQU 5C65h + + ld hl, (ATTR_T) + push hl ; Saves ATTR_T since BUG ROM changes it + + ld hl, (STK_END) + push hl ; Stores STK_END + + call __FPSTACK_PUSH ; Push number into stack + rst 28h ; # Rom Calculator + defb 2Eh ; # STR$(x) + defb 38h ; # END CALC + call __FPSTACK_POP ; Recovers string parameters to A ED CB + + pop hl + ld (STK_END), hl ; Balance STK_END to avoid STR$ bug + + pop hl + ld (ATTR_T), hl ; Restores ATTR_T + + ex de, hl ; String position now in HL + + push bc + xor a ; Avoid the str to be FREED from heap + call __PRINT_STR + pop bc + inc bc + + jp RECLAIM2 ; Frees TMP Memory + + RECLAIM2 EQU 19E8h + + ENDP + +#line 125 "read10.bas" +#line 1 "pstoref.asm" + + ; Stores FP number in A ED CB at location HL+IX + ; HL = Offset + ; IX = Stack Frame + ; A ED CB = FP Number + +#line 1 "storef.asm" + +__PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) + push de + ex de, hl ; DE <- HL + push ix + pop hl ; HL <- IX + add hl, de ; HL <- IX + HL + pop de + +__ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register + ex af, af' + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex af, af' + +__STOREF: ; Stores the given FP number in A EDCB at address HL + ld (hl), a + inc hl + ld (hl), e + inc hl + ld (hl), d + inc hl + ld (hl), c + inc hl + ld (hl), b + ret + +#line 7 "pstoref.asm" + + ; Stored a float number in A ED CB into the address pointed by IX + HL +__PSTOREF: + push de + ex de, hl ; DE <- HL + push ix + pop hl ; HL <- IX + add hl, de ; HL <- IX + DE + pop de + jp __STOREF + +#line 126 "read10.bas" +#line 1 "read_restore.asm" + + ;; This implements READ & RESTORE functions + ;; Reads a new element from the DATA Address code + ;; Updates the DATA_ADDR read ptr for the next read + + ;; Data codification is 1 byte for type followed by data bytes + ;; Byte type is encoded as follows + +;; 00: End of data +;; 01: String +;; 02: Byte +;; 03: Ubyte +;; 04: Integer +;; 05: UInteger +;; 06: Long +;; 07: ULong +;; 08: Fixed +;; 09: Float + + ;; bit7 is set for a parameter-less function + ;; In that case, the next two bytes are the ptr of the function to jump + + +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 24 "read_restore.asm" +#line 1 "iload32.asm" + + ; __FASTCALL__ routine which + ; loads a 32 bits integer into DE,HL + ; stored at position pointed by POINTER HL + ; DE,HL <-- (HL) + +__ILOAD32: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + ex de, hl + ret + +#line 25 "read_restore.asm" + +#line 1 "ftof16reg.asm" + +#line 1 "ftou32reg.asm" + +#line 1 "neg32.asm" + +__ABS32: + bit 7, d + ret z + +__NEG32: ; Negates DEHL (Two's complement) + ld a, l + cpl + ld l, a + + ld a, h + cpl + ld h, a + + ld a, e + cpl + ld e, a + + ld a, d + cpl + ld d, a + + inc l + ret nz + + inc h + ret nz + + inc de + ret + +#line 2 "ftou32reg.asm" + +__FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + ; Output: DEHL 32 bit number (signed) + PROC + + LOCAL __IS_FLOAT + + or a + jr nz, __IS_FLOAT + ; Here if it is a ZX ROM Integer + + ld h, c + ld l, d + ld a, e ; Takes sign: FF = -, 0 = + + ld de, 0 + inc a + jp z, __NEG32 ; Negates if negative + ret + +__IS_FLOAT: ; Jumps here if it is a true floating point number + ld h, e + push hl ; Stores it for later (Contains Sign in H) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + ;ld a, c ; Get exponent + sub 128 ; Exponent -= 128 + jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + +__FTOU32REG_LOOP: + exx ; Shift C'B' E'D' << 1, output bit stays in Carry + sla d + rl e + rl b + rl c + + exx ; Shift DEHL << 1, inserting the carry on the right + rl l + rl h + rl e + rl d + + djnz __FTOU32REG_LOOP + +__FTOU32REG_END: + pop af ; Take the sign bit + or a ; Sets SGN bit to 1 if negative + jp m, __NEG32 ; Negates DEHL + + ret + + ENDP + + +__FTOU8: ; Converts float in C ED LH to Unsigned byte in A + call __FTOU32REG + ld a, l + ret + +#line 2 "ftof16reg.asm" + +__FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + + ld l, a ; Saves exponent for later + or d + or e + or b + or c + ld h, e + ret z ; Return if ZERO + + push hl ; Stores it for later (Contains sign in H, exponent in L) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + pop bc + + ld a, c ; Get exponent + sub 112 ; Exponent -= 128 + 16 + + push bc ; Saves sign in b again + + jp z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jp c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + 16 (we need to shift 16 bit more) + jp __FTOU32REG_LOOP ; proceed as an u32 integer + +#line 27 "read_restore.asm" +#line 1 "f16tofreg.asm" + + +#line 1 "u32tofreg.asm" + + +__I8TOFREG: + ld l, a + rlca + sbc a, a ; A = SGN(A) + ld h, a + ld e, a + ld d, a + +__I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) + ; to a Floating Point Number returned in (A ED CB) + + ld a, d + or a ; Test sign + + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __U32TOFREG ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + +__U8TOFREG: + ; Converts an unsigned 8 bit (A) to Floating point + ld l, a + ld h, 0 + ld e, h + ld d, h + +__U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in A ED CB + + PROC + + LOCAL __U32TOFREG_END + + ld a, d + or e + or h + or l + ld b, d + ld c, e ; Returns 00 0000 0000 if ZERO + ret z + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 128 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + +__U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG + exx + ld a, d ; B'C'D'E' == 0 ? + or e + or b + or c + jp z, __U32TOFREG_END ; We are done + + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry + rr c + rr d + rr e + exx + + rr e ; Shift EDCB >> 1, inserting the carry on the left + rr d + rr c + rr b + + inc l ; Increment exponent + jp __U32TOFREG_LOOP + + +__U32TOFREG_END: + exx + ld a, l ; Puts the exponent in a + res 7, e ; Sets the sign bit to 0 (positive) + + ret + ENDP + +#line 3 "f16tofreg.asm" + +__F16TOFREG: ; Converts a 16.16 signed fixed point (stored in DEHL) + ; to a Floating Point Number returned in (C ED CB) + PROC + + LOCAL __F16TOFREG2 + + ld a, d + or a ; Test sign + + jp p, __F16TOFREG2 ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __F16TOFREG2 ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + + +__F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in C DE HL + + ld a, d + or e + or h + or l + ld b, h + ld c, l + ret z ; Return 00 0000 0000 if 0 + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 112 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + jp __U32TOFREG_LOOP ; Proceed as an integer + + ENDP + +#line 28 "read_restore.asm" + + + + + + + + + + + + + + ;; Updates restore point to the given HL mem. address +__RESTORE: + PROC + LOCAL __DATA_ADDR + + ld (__DATA_ADDR), hl + ret + + ;; Reads a value from the DATA mem area and updates __DATA_ADDR ptr to the + ;; next item. On Out Of Data, restarts + ;; +__READ: + LOCAL read_restart, cont, cont2, table, no_func + LOCAL dynamic_cast, dynamic_cast2, dynamic_cast3, dynamic_cast4 + LOCAL _decode_table, coerce_to_int, coerce_to_int2, promote_to_i16 + LOCAL _from_i8, _from_u8 + LOCAL _from_i16, _from_u16 + LOCAL _from_i32, _from_u32 + LOCAL _from_fixed, __data_error + + push af ; type of data to read + ld hl, (__DATA_ADDR) +read_restart: + ld a, (hl) + or a ; 0 => OUT of data + jr nz, cont + ;; Signals out of data + + ld hl, __DATA__0 + ld (__DATA_ADDR), hl + jr read_restart ; Start again +cont: + and 0x80 + ld a, (hl) + push af + jp z, no_func ;; Loads data directly, not a function + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl +cont2: + ld de, dynamic_cast + push de ; ret address + jp (hl) ; "call (hl)" + + ;; Now tries to convert the given result to the expected type or raise an error +dynamic_cast: + exx + ex af, af' + pop af ; type READ + and 0x7F ; clear bit 7 + pop hl ; type requested by USER (type of the READ variable) + ld c, h ; save requested type (save it in register C) + cp h + exx + jr nz, dynamic_cast2 ; Types are identical? + ;; yes, they are + ex af, af' + ret + +dynamic_cast2: + cp 1 ; Requested a number, but read a string? + jr nz, dynamic_cast3 + call __MEM_FREE ; Frees str from memory + jr __data_error + +dynamic_cast3: + exx + ld b, a ; Read type + ld a, c ; Requested type + cp 1 + jr z, __data_error + cp b + jr c, dynamic_cast4 + ;; here the user expected type is "larger" than the read one + ld a, b + sub 2 + add a, a + ld l, a + ld h, 0 + ld de, _decode_table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl + ld a, c ; Requested type + exx + ret + +__data_error: + ;; When a data is read, but cannot be converted to the requested type + ;; that is, the user asked for a string and we read a number or vice versa + ld a, ERROR_InvalidArg + call __STOP ; The user expected a string, but read a number + xor a + ld h, a + ld l, a + ld e, a + ld d, a + ld b, a + ld c, a + ret + +_decode_table: + dw _from_i8 + dw _from_u8 + dw _from_i16 + dw _from_u16 + dw _from_i32 + dw _from_u32 + dw _from_fixed + +_from_i8: + cp 4 + jr nc, promote_to_i16 + ex af, af' + ret ;; Was from Byte to Ubyte + +promote_to_i16: + ex af, af' + ld l, a + rla + sbc a, a + ld h, a ; copy sgn to h + ex af, af' + jr _before_from_i16 + +_from_u8: + ex af, af' + ld l, a + ld h, 0 + ex af, af' + ;; Promoted to i16 + +_before_from_i16: +_from_i16: + cp 6 + ret c ;; from i16 to u16 + ;; Promote i16 to i32 + ex af, af' + ld a, h + rla + sbc a, a + ld e, a + ld d, a + ex af, af' +_from_i32: + cp 7 + ret z ;; From i32 to u32 + ret c ;; From u16 to i32 + cp 9 + jp z, __I32TOFREG +_from_u32: + cp 9 + jp z, __U32TOFREG + ex de, hl + ld hl, 0 + cp 8 + ret z +_from_fixed: ;; From fixed to float + jp __F16TOFREG +_from_u16: + ld de, 0 ; HL 0x0000 => 32 bits + jp _from_i32 + +dynamic_cast4: + ;; The user type is "shorter" than the read one + cp 8 ;; required type + jr c, before_to_int ;; required < fixed (f16) + ex af, af' + exx ;; Ok, we must convert from float to f16 + jp __FTOF16REG + +before_to_int: + ld a, b ;; read type + cp 8 ;; + jr nz, coerce_to_int ;; From float to int + ld a, c ;; user type + exx + ;; f16 to Long + ex de, hl + ld a, h + rla + sbc a, a + ld d, a + ld e, a + exx + jr coerce_to_int2 +coerce_to_int: + exx + ex af, af' + call __FTOU32REG + ex af, af' ; a contains user type + exx +coerce_to_int2: ; At this point we have an u/integer in hl + exx + cp 4 + ret nc ; Already done. Return the result + ld a, l ; Truncate to byte + ret + +no_func: + exx + ld de, dynamic_cast + push de ; Ret address + dec a ; 0 => string; 1, 2 => byte; 3, 4 => integer; 5, 6 => long, 7 => fixed; 8 => float + ld h, 0 + add a, a + ld l, a + ld de, table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl ; address to jump to + exx + inc hl + ret ; jp (sp) => jump to table[a - 1] + +table: + LOCAL __01_decode_string + LOCAL __02_decode_byte + LOCAL __03_decode_ubyte + LOCAL __04_decode_integer + LOCAL __05_decode_uinteger + LOCAL __06_decode_long + LOCAL __07_decode_ulong + LOCAL __08_decode_fixed + LOCAL __09_decode_float + + ;; 1 -> Decode string + ;; 2, 3 -> Decode Byte, UByte + ;; 4, 5 -> Decode Integer, UInteger + ;; 6, 7 -> Decode Long, ULong + ;; 8 -> Decode Fixed + ;; 9 -> Decode Float + dw __01_decode_string + dw __02_decode_byte + dw __03_decode_ubyte + dw __04_decode_integer + dw __05_decode_uinteger + dw __06_decode_long + dw __07_decode_ulong + dw __08_decode_fixed + dw __09_decode_float + +__01_decode_string: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl + jp __LOADSTR + +__02_decode_byte: +__03_decode_ubyte: + ld a, (hl) + inc hl + ld (__DATA_ADDR), hl + ret + +__04_decode_integer: +__05_decode_uinteger: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl + ex de, hl + ret + +__06_decode_long: +__07_decode_ulong: +__08_decode_fixed: + ld b, h + ld c, l + inc bc + inc bc + inc bc + inc bc + ld (__DATA_ADDR), bc + jp __ILOAD32 + +__09_decode_float: + call __LOADF + inc hl + ld (__DATA_ADDR), hl + ld h, a ; returns A in H; sets A free + ret + +__DATA_ADDR: ;; Stores current DATA ptr + dw __DATA__0 + ENDP + + + + + + + + + + +#line 127 "read10.bas" +#line 1 "sin.asm" + + + +SIN: ; Computes SIN using ROM FP-CALC + call __FPSTACK_PUSH + + rst 28h ; ROM CALC + defb 1Fh + defb 38h ; END CALC + + jp __FPSTACK_POP + +#line 128 "read10.bas" +#line 1 "tan.asm" + + + +TAN: ; Computes TAN using ROM FP-CALC + call __FPSTACK_PUSH + + rst 28h ; ROM CALC + defb 21h ; TAN + defb 38h ; END CALC + + jp __FPSTACK_POP + +#line 129 "read10.bas" + +ZXBASIC_USER_DATA: +_v: + DEFB 81h + DEFB 40h + DEFB 00h + DEFB 00h + DEFB 00h +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/read10.bas b/tests/functional/read10.bas new file mode 100644 index 000000000..d4e4a225c --- /dev/null +++ b/tests/functional/read10.bas @@ -0,0 +1,21 @@ +REM Error x is an array, not an scalar + +DIM v as Float = 1.5 + +RESTORE + +DATA 10, 25 * v, SIN(v) * tan(v)^2, PI * v + + +function p() + DIM c as Float + FOR i = 0 TO 3: + READ c + PRINT c + NEXT i +end function +p() + + + + diff --git a/tests/functional/read12.asm b/tests/functional/read12.asm new file mode 100644 index 000000000..af088e720 --- /dev/null +++ b/tests/functional/read12.asm @@ -0,0 +1,2612 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + call __PRINT_INIT + ld hl, __DATA__1 + call __RESTORE + ld a, 2 + call __READ + ld (_a), a + call __PRINTI8 + call PRINT_EOL + ld a, 2 + call __READ + ld (_a), a + call __PRINTI8 + call PRINT_EOL +__LABEL__test: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +___DATA__FUNCPTR__0: + ld hl, __LABEL0 + call __LOADSTR + jp ___DATA__FUNCPTR__0__leave +___DATA__FUNCPTR__0__leave: + ret +__DATA__0: + DEFB 81h + DEFW ___DATA__FUNCPTR__0 +__DATA__1: + DEFB 3 + DEFB 1 + DEFB 3 + DEFB 2 +__DATA__END: + DEFB 00h +__LABEL0: + DEFW 0004h + DEFB 68h + DEFB 6Fh + DEFB 6Ch + DEFB 61h +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 69 "alloc.asm" +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 70 "alloc.asm" + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 53 "read12.bas" +#line 1 "print.asm" + +; vim:ts=4:sw=4:et: + ; PRINT command routine + ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that + +#line 1 "sposn.asm" + + ; Printing positioning library. + PROC + LOCAL ECHO_E + +__LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. + ld de, (S_POSN) + ld hl, (MAXX) + or a + sbc hl, de + ex de, hl + ret + + +__SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. + ld hl, (MAXX) + or a + sbc hl, de + ld (S_POSN), hl ; saves it again + ret + + + ECHO_E EQU 23682 + MAXX EQU ECHO_E ; Max X position + 1 + MAXY EQU MAXX + 1 ; Max Y position + 1 + + S_POSN EQU 23688 + POSX EQU S_POSN ; Current POS X + POSY EQU S_POSN + 1 ; Current POS Y + + ENDP + +#line 6 "print.asm" +#line 1 "cls.asm" + + ; JUMPS directly to spectrum CLS + ; This routine does not clear lower screen + + ;CLS EQU 0DAFh + + ; Our faster implementation + + + +CLS: + PROC + + LOCAL COORDS + LOCAL __CLS_SCR + LOCAL ATTR_P + LOCAL SCREEN + + ld hl, 0 + ld (COORDS), hl + ld hl, 1821h + ld (S_POSN), hl +__CLS_SCR: + ld hl, SCREEN + ld (hl), 0 + ld d, h + ld e, l + inc de + ld bc, 6144 + ldir + + ; Now clear attributes + + ld a, (ATTR_P) + ld (hl), a + ld bc, 767 + ldir + ret + + COORDS EQU 23677 + SCREEN EQU 16384 ; Default start of the screen (can be changed) + ATTR_P EQU 23693 + ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address + + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines + ; to get the start of the screen + ENDP + +#line 7 "print.asm" +#line 1 "in_screen.asm" + + + + +__IN_SCREEN: + ; Returns NO carry if current coords (D, E) + ; are OUT of the screen limits (MAXX, MAXY) + + PROC + LOCAL __IN_SCREEN_ERR + + ld hl, MAXX + ld a, e + cp (hl) + jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + + ld a, d + inc hl + cp (hl) + ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + ;; ret + ret c ; Return if carry (OK) + +__IN_SCREEN_ERR: +__OUT_OF_SCREEN_ERR: + ; Jumps here if out of screen + ld a, ERROR_OutOfScreen + jp __STOP ; Saves error code and exits + + ENDP +#line 8 "print.asm" +#line 1 "table_jump.asm" + + +JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A + add a, a + +JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE + ld e, a + ld d, 0 + +JUMP_HL_PLUS_DE: ; Does JP (HL + DE) + add hl, de + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl +CALL_HL: + jp (hl) + +#line 9 "print.asm" +#line 1 "ink.asm" + + ; Sets ink color in ATTR_P permanently +; Parameter: Paper color in A register + +#line 1 "const.asm" + + ; Global constants + + P_FLAG EQU 23697 + FLAGS2 EQU 23681 + ATTR_P EQU 23693 ; permanet ATTRIBUTES + ATTR_T EQU 23695 ; temporary ATTRIBUTES + CHARS EQU 23606 ; Pointer to ROM/RAM Charset + UDG EQU 23675 ; Pointer to UDG Charset + MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars + +#line 5 "ink.asm" + +INK: + PROC + LOCAL __SET_INK + LOCAL __SET_INK2 + + ld de, ATTR_P + +__SET_INK: + cp 8 + jr nz, __SET_INK2 + + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + or 7 ; Set bits 0,1,2 to enable transparency + ld (de), a + ret + +__SET_INK2: + ; Another entry. This will set the ink color at location pointer by DE + and 7 ; # Gets color mod 8 + ld b, a ; Saves the color + ld a, (de) + and 0F8h ; Clears previous value + or b + ld (de), a + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + and 0F8h ; Reset bits 0,1,2 sign to disable transparency + ld (de), a ; Store new attr + ret + + ; Sets the INK color passed in A register in the ATTR_T variable +INK_TMP: + ld de, ATTR_T + jp __SET_INK + + ENDP + +#line 10 "print.asm" +#line 1 "paper.asm" + + ; Sets paper color in ATTR_P permanently +; Parameter: Paper color in A register + + + +PAPER: + PROC + LOCAL __SET_PAPER + LOCAL __SET_PAPER2 + + ld de, ATTR_P + +__SET_PAPER: + cp 8 + jr nz, __SET_PAPER2 + inc de + ld a, (de) + or 038h + ld (de), a + ret + + ; Another entry. This will set the paper color at location pointer by DE +__SET_PAPER2: + and 7 ; # Remove + rlca + rlca + rlca ; a *= 8 + + ld b, a ; Saves the color + ld a, (de) + and 0C7h ; Clears previous value + or b + ld (de), a + inc de ; Points to MASK_T or MASK_P accordingly + ld a, (de) + and 0C7h ; Resets bits 3,4,5 + ld (de), a + ret + + + ; Sets the PAPER color passed in A register in the ATTR_T variable +PAPER_TMP: + ld de, ATTR_T + jp __SET_PAPER + ENDP + +#line 11 "print.asm" +#line 1 "flash.asm" + + ; Sets flash flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +FLASH: + ld de, ATTR_P +__SET_FLASH: + ; Another entry. This will set the flash flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + ld b, a ; Saves the color + ld a, (de) + and 07Fh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the FLASH flag passed in A register in the ATTR_T variable +FLASH_TMP: + ld de, ATTR_T + jr __SET_FLASH + +#line 12 "print.asm" +#line 1 "bright.asm" + + ; Sets bright flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +BRIGHT: + ld de, ATTR_P + +__SET_BRIGHT: + ; Another entry. This will set the bright flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + rrca + ld b, a ; Saves the color + ld a, (de) + and 0BFh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable +BRIGHT_TMP: + ld de, ATTR_T + jr __SET_BRIGHT + +#line 13 "print.asm" +#line 1 "over.asm" + + ; Sets OVER flag in P_FLAG permanently +; Parameter: OVER flag in bit 0 of A register +#line 1 "copy_attr.asm" + + + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" + + + +COPY_ATTR: + ; Just copies current permanent attribs to temporal attribs + ; and sets print mode + PROC + + LOCAL INVERSE1 + LOCAL __REFRESH_TMP + + INVERSE1 EQU 02Fh + + ld hl, (ATTR_P) + ld (ATTR_T), hl + + ld hl, FLAGS2 + call __REFRESH_TMP + + ld hl, P_FLAG + call __REFRESH_TMP + + +__SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) + + + LOCAL TABLE + LOCAL CONT2 + + rra ; Over bit to carry + ld a, (FLAGS2) + rla ; Over bit in bit 1, Over2 bit in bit 2 + and 3 ; Only bit 0 and 1 (OVER flag) + + ld c, a + ld b, 0 + + ld hl, TABLE + add hl, bc + ld a, (hl) + ld (PRINT_MODE), a + + ld hl, (P_FLAG) + xor a ; NOP -> INVERSE0 + bit 2, l + jr z, CONT2 + ld a, INVERSE1 ; CPL -> INVERSE1 + +CONT2: + ld (INVERSE_MODE), a + ret + +TABLE: + nop ; NORMAL MODE + xor (hl) ; OVER 1 MODE + and (hl) ; OVER 2 MODE + or (hl) ; OVER 3 MODE + +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" + +__REFRESH_TMP: + ld a, (hl) + and 10101010b + ld c, a + rra + or c + ld (hl), a + ret + + ENDP + +#line 4 "over.asm" + + +OVER: + PROC + + ld c, a ; saves it for later + and 2 + ld hl, FLAGS2 + res 1, (HL) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 ; # Convert to 0/1 + add a, a; # Shift left 1 bit for permanent + + ld hl, P_FLAG + res 1, (hl) + or (hl) + ld (hl), a + ret + + ; Sets OVER flag in P_FLAG temporarily +OVER_TMP: + ld c, a ; saves it for later + and 2 ; gets bit 1; clears carry + rra + ld hl, FLAGS2 + res 0, (hl) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 + ld hl, P_FLAG + res 0, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 14 "print.asm" +#line 1 "inverse.asm" + + ; Sets INVERSE flag in P_FLAG permanently +; Parameter: INVERSE flag in bit 0 of A register + + + +INVERSE: + PROC + + and 1 ; # Convert to 0/1 + add a, a; # Shift left 3 bits for permanent + add a, a + add a, a + ld hl, P_FLAG + res 3, (hl) + or (hl) + ld (hl), a + ret + + ; Sets INVERSE flag in P_FLAG temporarily +INVERSE_TMP: + and 1 + add a, a + add a, a; # Shift left 2 bits for temporary + ld hl, P_FLAG + res 2, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 15 "print.asm" +#line 1 "bold.asm" + + ; Sets BOLD flag in P_FLAG permanently +; Parameter: BOLD flag in bit 0 of A register + + +BOLD: + PROC + + and 1 + rlca + rlca + rlca + ld hl, FLAGS2 + res 3, (HL) + or (hl) + ld (hl), a + ret + + ; Sets BOLD flag in P_FLAG temporarily +BOLD_TMP: + and 1 + rlca + rlca + ld hl, FLAGS2 + res 2, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 16 "print.asm" +#line 1 "italic.asm" + + ; Sets ITALIC flag in P_FLAG permanently +; Parameter: ITALIC flag in bit 0 of A register + + +ITALIC: + PROC + + and 1 + rrca + rrca + rrca + ld hl, FLAGS2 + res 5, (HL) + or (hl) + ld (hl), a + ret + + ; Sets ITALIC flag in P_FLAG temporarily +ITALIC_TMP: + and 1 + rrca + rrca + rrca + rrca + ld hl, FLAGS2 + res 4, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 17 "print.asm" + +#line 1 "attr.asm" + + ; Attribute routines +; vim:ts=4:et:sw: + + + + + + + +__ATTR_ADDR: + ; calc start address in DE (as (32 * d) + e) + ; Contributed by Santiago Romero at http://www.speccy.org + ld h, 0 ; 7 T-States + ld a, d ; 4 T-States + add a, a ; a * 2 ; 4 T-States + add a, a ; a * 4 ; 4 T-States + ld l, a ; HL = A * 4 ; 4 T-States + + add hl, hl ; HL = A * 8 ; 15 T-States + add hl, hl ; HL = A * 16 ; 15 T-States + add hl, hl ; HL = A * 32 ; 15 T-States + + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) + add hl, de + + ld de, (SCREEN_ADDR) ; Adds the screen address + add hl, de + + ; Return current screen address in HL + ret + + + ; Sets the attribute at a given screen coordinate (D, E). + ; The attribute is taken from the ATTR_T memory variable + ; Used by PRINT routines +SET_ATTR: + + ; Checks for valid coords + call __IN_SCREEN + ret nc + +__SET_ATTR: + ; Internal __FASTCALL__ Entry used by printing routines + PROC + + call __ATTR_ADDR + ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T + + ld a, d + and (hl) + ld c, a ; C = current screen color, masked + + ld a, d + cpl ; Negate mask + and e ; Mask current attributes + or c ; Mix them + ld (hl), a ; Store result in screen + + ret + + ENDP + + +#line 19 "print.asm" + + ; Putting a comment starting with @INIT
+ ; will make the compiler to add a CALL to
+ ; It is useful for initialization routines. + + +__PRINT_INIT: ; To be called before program starts (initializes library) + PROC + + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + + ld hl, 1821h + ld (MAXX), hl ; Sets current maxX and maxY + + xor a + ld (FLAGS2), a + + ret + + +__PRINTCHAR: ; Print character store in accumulator (A register) + ; Modifies H'L', B'C', A'F', D'E', A + + LOCAL PO_GR_1 + + LOCAL __PRCHAR + LOCAL __PRINT_CONT + LOCAL __PRINT_CONT2 + LOCAL __PRINT_JUMP + LOCAL __SRCADDR + LOCAL __PRINT_UDG + LOCAL __PRGRAPH + LOCAL __PRINT_START + + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 + +__PRINT_JUMP: + jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively + +__PRINT_START: + cp ' ' + jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones + + exx ; Switch to alternative registers + ex af, af' ; Saves a value (char to print) for later + + call __LOAD_S_POSN + + ; At this point we have the new coord + ld hl, (SCREEN_ADDR) + + ld a, d + ld c, a ; Saves it for later + + and 0F8h ; Masks 3 lower bit ; zy + ld d, a + + ld a, c ; Recovers it + and 07h ; MOD 7 ; y1 + rrca + rrca + rrca + + or e + ld e, a + add hl, de ; HL = Screen address + DE + ex de, hl ; DE = Screen address + + ex af, af' + + cp 80h ; Is it an UDG or a ? + jp c, __SRCADDR + + cp 90h + jp nc, __PRINT_UDG + + ; Print a 8 bit pattern (80h to 8Fh) + + ld b, a + call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 + ld hl, MEM0 + jp __PRGRAPH + + PO_GR_1 EQU 0B38h + +__PRINT_UDG: + sub 90h ; Sub ASC code + ld bc, (UDG) + jp __PRGRAPH0 + + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source +__SRCADDR: + ld bc, (CHARS) + +__PRGRAPH0: + add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org + ld l, a + ld h, 0 ; HL = a * 2 (accumulator) + add hl, hl + add hl, hl ; HL = a * 8 + add hl, bc ; HL = CHARS address + +__PRGRAPH: + ex de, hl ; HL = Write Address, DE = CHARS address + bit 2, (iy + $47) + call nz, __BOLD + bit 4, (iy + $47) + call nz, __ITALIC + ld b, 8 ; 8 bytes per char +__PRCHAR: + ld a, (de) ; DE *must* be ALWAYS source, and HL destiny + +PRINT_MODE: ; Which operation is used to write on the screen + ; Set it with: + ; LD A, + ; LD (PRINT_MODE), A + ; + ; Available opertions: + ; NORMAL: 0h --> NOP ; OVER 0 + ; XOR : AEh --> XOR (HL) ; OVER 1 + ; OR : B6h --> OR (HL) ; PUTSPRITE + ; AND : A6h --> AND (HL) ; PUTMASK + nop ; + +INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 + nop ; 2F -> CPL -> INVERSE 1 + + ld (hl), a + + inc de + inc h ; Next line + djnz __PRCHAR + + call __LOAD_S_POSN + push de + call __SET_ATTR + pop de + inc e ; COL = COL + 1 + ld hl, (MAXX) + ld a, e + dec l ; l = MAXX + cp l ; Lower than max? + jp c, __PRINT_CONT; Nothing to do + call __PRINT_EOL1 + exx ; counteracts __PRINT_EOL1 exx + jp __PRINT_CONT2 + +__PRINT_CONT: + call __SAVE_S_POSN + +__PRINT_CONT2: + exx + ret + + ; ------------- SPECIAL CHARS (< 32) ----------------- + +__PRINT_SPECIAL: ; Jumps here if it is a special char + exx + ld hl, __PRINT_TABLE + jp JUMP_HL_PLUS_2A + + +PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence + exx + +__PRINT_0Dh: ; Called WHEN printing CHR$(13) + call __LOAD_S_POSN + +__PRINT_EOL1: ; Another entry called from PRINT when next line required + ld e, 0 + +__PRINT_EOL2: + ld a, d + inc a + +__PRINT_AT1_END: + ld hl, (MAXY) + cp l + jr c, __PRINT_EOL_END ; Carry if (MAXY) < d + xor a + +__PRINT_EOL_END: + ld d, a + +__PRINT_AT2_END: + call __SAVE_S_POSN + exx + ret + +__PRINT_COM: + exx + push hl + push de + push bc + call PRINT_COMMA + pop bc + pop de + pop hl + ret + +__PRINT_TAB: + ld hl, __PRINT_TAB1 + jp __PRINT_SET_STATE + +__PRINT_TAB1: + ld (MEM0), a + ld hl, __PRINT_TAB2 + ld (PRINT_JUMP_STATE), hl + ret + +__PRINT_TAB2: + ld a, (MEM0) ; Load tab code (ignore the current one) + push hl + push de + push bc + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + call PRINT_TAB + pop bc + pop de + pop hl + ret + +__PRINT_NOP: +__PRINT_RESTART: + ld hl, __PRINT_START + jp __PRINT_SET_STATE + +__PRINT_AT: + ld hl, __PRINT_AT1 + +__PRINT_SET_STATE: + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + exx + ret + +__PRINT_AT1: ; Jumps here if waiting for 1st parameter + exx + ld hl, __PRINT_AT2 + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + jp __PRINT_AT1_END + +__PRINT_AT2: + exx + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + ld e, a + ld hl, (MAXX) + cp (hl) + jr c, __PRINT_AT2_END + jr __PRINT_EOL1 + +__PRINT_DEL: + call __LOAD_S_POSN ; Gets current screen position + dec e + ld a, -1 + cp e + jp nz, __PRINT_AT2_END + ld hl, (MAXX) + ld e, l + dec e + dec e + dec d + cp d + jp nz, __PRINT_AT2_END + ld d, h + dec d + jp __PRINT_AT2_END + +__PRINT_INK: + ld hl, __PRINT_INK2 + jp __PRINT_SET_STATE + +__PRINT_INK2: + exx + call INK_TMP + jp __PRINT_RESTART + +__PRINT_PAP: + ld hl, __PRINT_PAP2 + jp __PRINT_SET_STATE + +__PRINT_PAP2: + exx + call PAPER_TMP + jp __PRINT_RESTART + +__PRINT_FLA: + ld hl, __PRINT_FLA2 + jp __PRINT_SET_STATE + +__PRINT_FLA2: + exx + call FLASH_TMP + jp __PRINT_RESTART + +__PRINT_BRI: + ld hl, __PRINT_BRI2 + jp __PRINT_SET_STATE + +__PRINT_BRI2: + exx + call BRIGHT_TMP + jp __PRINT_RESTART + +__PRINT_INV: + ld hl, __PRINT_INV2 + jp __PRINT_SET_STATE + +__PRINT_INV2: + exx + call INVERSE_TMP + jp __PRINT_RESTART + +__PRINT_OVR: + ld hl, __PRINT_OVR2 + jp __PRINT_SET_STATE + +__PRINT_OVR2: + exx + call OVER_TMP + jp __PRINT_RESTART + +__PRINT_BOLD: + ld hl, __PRINT_BOLD2 + jp __PRINT_SET_STATE + +__PRINT_BOLD2: + exx + call BOLD_TMP + jp __PRINT_RESTART + +__PRINT_ITA: + ld hl, __PRINT_ITA2 + jp __PRINT_SET_STATE + +__PRINT_ITA2: + exx + call ITALIC_TMP + jp __PRINT_RESTART + + +__BOLD: + push hl + ld hl, MEM0 + ld b, 8 +__BOLD_LOOP: + ld a, (de) + ld c, a + rlca + or c + ld (hl), a + inc hl + inc de + djnz __BOLD_LOOP + pop hl + ld de, MEM0 + ret + + +__ITALIC: + push hl + ld hl, MEM0 + ex de, hl + ld bc, 8 + ldir + ld hl, MEM0 + srl (hl) + inc hl + srl (hl) + inc hl + srl (hl) + inc hl + inc hl + inc hl + sla (hl) + inc hl + sla (hl) + inc hl + sla (hl) + pop hl + ld de, MEM0 + ret + +PRINT_COMMA: + call __LOAD_S_POSN + ld a, e + and 16 + add a, 16 + +PRINT_TAB: + PROC + LOCAL LOOP, CONTINUE + + inc a + call __LOAD_S_POSN ; e = current row + ld d, a + ld a, e + cp 21h + jr nz, CONTINUE + ld e, -1 +CONTINUE: + ld a, d + inc e + sub e ; A = A - E + and 31 ; + ret z ; Already at position E + ld b, a +LOOP: + ld a, ' ' + call __PRINTCHAR + djnz LOOP + ret + ENDP + +PRINT_AT: ; CHanges cursor to ROW, COL + ; COL in A register + ; ROW in stack + + pop hl ; Ret address + ex (sp), hl ; callee H = ROW + ld l, a + ex de, hl + + call __IN_SCREEN + ret nc ; Return if out of screen + + jp __SAVE_S_POSN + + LOCAL __PRINT_COM + LOCAL __BOLD + LOCAL __BOLD_LOOP + LOCAL __ITALIC + LOCAL __PRINT_EOL1 + LOCAL __PRINT_EOL2 + LOCAL __PRINT_AT1 + LOCAL __PRINT_AT2 + LOCAL __PRINT_AT2_END + LOCAL __PRINT_BOLD + LOCAL __PRINT_BOLD2 + LOCAL __PRINT_ITA + LOCAL __PRINT_ITA2 + LOCAL __PRINT_INK + LOCAL __PRINT_PAP + LOCAL __PRINT_SET_STATE + LOCAL __PRINT_TABLE + LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 + +__PRINT_TABLE: ; Jump table for 0 .. 22 codes + + DW __PRINT_NOP ; 0 + DW __PRINT_NOP ; 1 + DW __PRINT_NOP ; 2 + DW __PRINT_NOP ; 3 + DW __PRINT_NOP ; 4 + DW __PRINT_NOP ; 5 + DW __PRINT_COM ; 6 COMMA + DW __PRINT_NOP ; 7 + DW __PRINT_DEL ; 8 DEL + DW __PRINT_NOP ; 9 + DW __PRINT_NOP ; 10 + DW __PRINT_NOP ; 11 + DW __PRINT_NOP ; 12 + DW __PRINT_0Dh ; 13 + DW __PRINT_BOLD ; 14 + DW __PRINT_ITA ; 15 + DW __PRINT_INK ; 16 + DW __PRINT_PAP ; 17 + DW __PRINT_FLA ; 18 + DW __PRINT_BRI ; 19 + DW __PRINT_INV ; 20 + DW __PRINT_OVR ; 21 + DW __PRINT_AT ; 22 AT + DW __PRINT_TAB ; 23 TAB + + ENDP + + +#line 54 "read12.bas" +#line 1 "printi8.asm" + +#line 1 "printnum.asm" + + + + +__PRINTU_START: + PROC + + LOCAL __PRINTU_CONT + + ld a, b + or a + jp nz, __PRINTU_CONT + + ld a, '0' + jp __PRINT_DIGIT + + +__PRINTU_CONT: + pop af + push bc + call __PRINT_DIGIT + pop bc + djnz __PRINTU_CONT + ret + + ENDP + + +__PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers + ld a, '-' + jp __PRINT_DIGIT + + __PRINT_DIGIT EQU __PRINTCHAR ; PRINTS the char in A register, and puts its attrs + + +#line 2 "printi8.asm" +#line 1 "div8.asm" + + ; -------------------------------- +__DIVU8: ; 8 bit unsigned integer division + ; Divides (Top of stack, High Byte) / A + pop hl ; -------------------------------- + ex (sp), hl ; CALLEE + +__DIVU8_FAST: ; Does A / H + ld l, h + ld h, a ; At this point do H / L + + ld b, 8 + xor a ; A = 0, Carry Flag = 0 + +__DIV8LOOP: + sla h + rla + cp l + jr c, __DIV8NOSUB + sub l + inc h + +__DIV8NOSUB: + djnz __DIV8LOOP + + ld l, a ; save remainder + ld a, h ; + + ret ; a = Quotient, + + + ; -------------------------------- +__DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A + pop hl ; -------------------------------- + ex (sp), hl + +__DIVI8_FAST: + ld e, a ; store operands for later + ld c, h + + or a ; negative? + jp p, __DIV8A + neg ; Make it positive + +__DIV8A: + ex af, af' + ld a, h + or a + jp p, __DIV8B + neg + ld h, a ; make it positive + +__DIV8B: + ex af, af' + + call __DIVU8_FAST + + ld a, c + xor l ; bit 7 of A = 1 if result is negative + + ld a, h ; Quotient + ret p ; return if positive + + neg + ret + + +__MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) + pop hl + ex (sp), hl ; CALLEE + +__MODU8_FAST: ; __FASTCALL__ entry + call __DIVU8_FAST + ld a, l ; Remainder + + ret ; a = Modulus + + +__MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) + pop hl + ex (sp), hl ; CALLEE + +__MODI8_FAST: ; __FASTCALL__ entry + call __DIVI8_FAST + ld a, l ; remainder + + ret ; a = Modulus + +#line 3 "printi8.asm" + +__PRINTI8: ; Prints an 8 bits number in Accumulator (A) + ; Converts 8 to 32 bits + or a + jp p, __PRINTU8 + + push af + call __PRINT_MINUS + pop af + neg + +__PRINTU8: + PROC + + LOCAL __PRINTU_LOOP + + ld b, 0 ; Counter + +__PRINTU_LOOP: + or a + jp z, __PRINTU_START + + push bc + ld h, 10 + call __DIVU8_FAST ; Divides by 10. D'E'H'L' contains modulo (L' since < 10) + pop bc + + ld a, l + or '0' ; Stores ASCII digit (must be print in reversed order) + push af + ld a, h + inc b + jp __PRINTU_LOOP ; Uses JP in loops + + ENDP + +#line 55 "read12.bas" +#line 1 "read_restore.asm" + + ;; This implements READ & RESTORE functions + ;; Reads a new element from the DATA Address code + ;; Updates the DATA_ADDR read ptr for the next read + + ;; Data codification is 1 byte for type followed by data bytes + ;; Byte type is encoded as follows + +;; 00: End of data +;; 01: String +;; 02: Byte +;; 03: Ubyte +;; 04: Integer +;; 05: UInteger +;; 06: Long +;; 07: ULong +;; 08: Fixed +;; 09: Float + + ;; bit7 is set for a parameter-less function + ;; In that case, the next two bytes are the ptr of the function to jump + + + +#line 1 "iload32.asm" + + ; __FASTCALL__ routine which + ; loads a 32 bits integer into DE,HL + ; stored at position pointed by POINTER HL + ; DE,HL <-- (HL) + +__ILOAD32: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + ex de, hl + ret + +#line 25 "read_restore.asm" +#line 1 "iloadf.asm" + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- ((HL)) + +__ILOADF: + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- (HL) + +__LOADF: ; Loads a 40 bits FP number from address pointed by HL + ld a, (hl) + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld c, (hl) + inc hl + ld b, (hl) + ret + +#line 26 "read_restore.asm" +#line 1 "ftof16reg.asm" + +#line 1 "ftou32reg.asm" + +#line 1 "neg32.asm" + +__ABS32: + bit 7, d + ret z + +__NEG32: ; Negates DEHL (Two's complement) + ld a, l + cpl + ld l, a + + ld a, h + cpl + ld h, a + + ld a, e + cpl + ld e, a + + ld a, d + cpl + ld d, a + + inc l + ret nz + + inc h + ret nz + + inc de + ret + +#line 2 "ftou32reg.asm" + +__FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + ; Output: DEHL 32 bit number (signed) + PROC + + LOCAL __IS_FLOAT + + or a + jr nz, __IS_FLOAT + ; Here if it is a ZX ROM Integer + + ld h, c + ld l, d + ld a, e ; Takes sign: FF = -, 0 = + + ld de, 0 + inc a + jp z, __NEG32 ; Negates if negative + ret + +__IS_FLOAT: ; Jumps here if it is a true floating point number + ld h, e + push hl ; Stores it for later (Contains Sign in H) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + ;ld a, c ; Get exponent + sub 128 ; Exponent -= 128 + jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + +__FTOU32REG_LOOP: + exx ; Shift C'B' E'D' << 1, output bit stays in Carry + sla d + rl e + rl b + rl c + + exx ; Shift DEHL << 1, inserting the carry on the right + rl l + rl h + rl e + rl d + + djnz __FTOU32REG_LOOP + +__FTOU32REG_END: + pop af ; Take the sign bit + or a ; Sets SGN bit to 1 if negative + jp m, __NEG32 ; Negates DEHL + + ret + + ENDP + + +__FTOU8: ; Converts float in C ED LH to Unsigned byte in A + call __FTOU32REG + ld a, l + ret + +#line 2 "ftof16reg.asm" + +__FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + + ld l, a ; Saves exponent for later + or d + or e + or b + or c + ld h, e + ret z ; Return if ZERO + + push hl ; Stores it for later (Contains sign in H, exponent in L) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + pop bc + + ld a, c ; Get exponent + sub 112 ; Exponent -= 128 + 16 + + push bc ; Saves sign in b again + + jp z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jp c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + 16 (we need to shift 16 bit more) + jp __FTOU32REG_LOOP ; proceed as an u32 integer + +#line 27 "read_restore.asm" +#line 1 "f16tofreg.asm" + + +#line 1 "u32tofreg.asm" + + +__I8TOFREG: + ld l, a + rlca + sbc a, a ; A = SGN(A) + ld h, a + ld e, a + ld d, a + +__I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) + ; to a Floating Point Number returned in (A ED CB) + + ld a, d + or a ; Test sign + + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __U32TOFREG ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + +__U8TOFREG: + ; Converts an unsigned 8 bit (A) to Floating point + ld l, a + ld h, 0 + ld e, h + ld d, h + +__U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in A ED CB + + PROC + + LOCAL __U32TOFREG_END + + ld a, d + or e + or h + or l + ld b, d + ld c, e ; Returns 00 0000 0000 if ZERO + ret z + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 128 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + +__U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG + exx + ld a, d ; B'C'D'E' == 0 ? + or e + or b + or c + jp z, __U32TOFREG_END ; We are done + + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry + rr c + rr d + rr e + exx + + rr e ; Shift EDCB >> 1, inserting the carry on the left + rr d + rr c + rr b + + inc l ; Increment exponent + jp __U32TOFREG_LOOP + + +__U32TOFREG_END: + exx + ld a, l ; Puts the exponent in a + res 7, e ; Sets the sign bit to 0 (positive) + + ret + ENDP + +#line 3 "f16tofreg.asm" + +__F16TOFREG: ; Converts a 16.16 signed fixed point (stored in DEHL) + ; to a Floating Point Number returned in (C ED CB) + PROC + + LOCAL __F16TOFREG2 + + ld a, d + or a ; Test sign + + jp p, __F16TOFREG2 ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __F16TOFREG2 ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + + +__F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in C DE HL + + ld a, d + or e + or h + or l + ld b, h + ld c, l + ret z ; Return 00 0000 0000 if 0 + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 112 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + jp __U32TOFREG_LOOP ; Proceed as an integer + + ENDP + +#line 28 "read_restore.asm" +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 29 "read_restore.asm" + + + + + + + + + + + + + ;; Updates restore point to the given HL mem. address +__RESTORE: + PROC + LOCAL __DATA_ADDR + + ld (__DATA_ADDR), hl + ret + + ;; Reads a value from the DATA mem area and updates __DATA_ADDR ptr to the + ;; next item. On Out Of Data, restarts + ;; +__READ: + LOCAL read_restart, cont, cont2, table, no_func + LOCAL dynamic_cast, dynamic_cast2, dynamic_cast3, dynamic_cast4 + LOCAL _decode_table, coerce_to_int, coerce_to_int2, promote_to_i16 + LOCAL _from_i8, _from_u8 + LOCAL _from_i16, _from_u16 + LOCAL _from_i32, _from_u32 + LOCAL _from_fixed, __data_error + + push af ; type of data to read + ld hl, (__DATA_ADDR) +read_restart: + ld a, (hl) + or a ; 0 => OUT of data + jr nz, cont + ;; Signals out of data + + ld hl, __DATA__0 + ld (__DATA_ADDR), hl + jr read_restart ; Start again +cont: + and 0x80 + ld a, (hl) + push af + jp z, no_func ;; Loads data directly, not a function + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl +cont2: + ld de, dynamic_cast + push de ; ret address + jp (hl) ; "call (hl)" + + ;; Now tries to convert the given result to the expected type or raise an error +dynamic_cast: + exx + ex af, af' + pop af ; type READ + and 0x7F ; clear bit 7 + pop hl ; type requested by USER (type of the READ variable) + ld c, h ; save requested type (save it in register C) + cp h + exx + jr nz, dynamic_cast2 ; Types are identical? + ;; yes, they are + ex af, af' + ret + +dynamic_cast2: + cp 1 ; Requested a number, but read a string? + jr nz, dynamic_cast3 + call __MEM_FREE ; Frees str from memory + jr __data_error + +dynamic_cast3: + exx + ld b, a ; Read type + ld a, c ; Requested type + cp 1 + jr z, __data_error + cp b + jr c, dynamic_cast4 + ;; here the user expected type is "larger" than the read one + ld a, b + sub 2 + add a, a + ld l, a + ld h, 0 + ld de, _decode_table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl + ld a, c ; Requested type + exx + ret + +__data_error: + ;; When a data is read, but cannot be converted to the requested type + ;; that is, the user asked for a string and we read a number or vice versa + ld a, ERROR_InvalidArg + call __STOP ; The user expected a string, but read a number + xor a + ld h, a + ld l, a + ld e, a + ld d, a + ld b, a + ld c, a + ret + +_decode_table: + dw _from_i8 + dw _from_u8 + dw _from_i16 + dw _from_u16 + dw _from_i32 + dw _from_u32 + dw _from_fixed + +_from_i8: + cp 4 + jr nc, promote_to_i16 + ex af, af' + ret ;; Was from Byte to Ubyte + +promote_to_i16: + ex af, af' + ld l, a + rla + sbc a, a + ld h, a ; copy sgn to h + ex af, af' + jr _before_from_i16 + +_from_u8: + ex af, af' + ld l, a + ld h, 0 + ex af, af' + ;; Promoted to i16 + +_before_from_i16: +_from_i16: + cp 6 + ret c ;; from i16 to u16 + ;; Promote i16 to i32 + ex af, af' + ld a, h + rla + sbc a, a + ld e, a + ld d, a + ex af, af' +_from_i32: + cp 7 + ret z ;; From i32 to u32 + ret c ;; From u16 to i32 + cp 9 + jp z, __I32TOFREG +_from_u32: + cp 9 + jp z, __U32TOFREG + ex de, hl + ld hl, 0 + cp 8 + ret z +_from_fixed: ;; From fixed to float + jp __F16TOFREG +_from_u16: + ld de, 0 ; HL 0x0000 => 32 bits + jp _from_i32 + +dynamic_cast4: + ;; The user type is "shorter" than the read one + cp 8 ;; required type + jr c, before_to_int ;; required < fixed (f16) + ex af, af' + exx ;; Ok, we must convert from float to f16 + jp __FTOF16REG + +before_to_int: + ld a, b ;; read type + cp 8 ;; + jr nz, coerce_to_int ;; From float to int + ld a, c ;; user type + exx + ;; f16 to Long + ex de, hl + ld a, h + rla + sbc a, a + ld d, a + ld e, a + exx + jr coerce_to_int2 +coerce_to_int: + exx + ex af, af' + call __FTOU32REG + ex af, af' ; a contains user type + exx +coerce_to_int2: ; At this point we have an u/integer in hl + exx + cp 4 + ret nc ; Already done. Return the result + ld a, l ; Truncate to byte + ret + +no_func: + exx + ld de, dynamic_cast + push de ; Ret address + dec a ; 0 => string; 1, 2 => byte; 3, 4 => integer; 5, 6 => long, 7 => fixed; 8 => float + ld h, 0 + add a, a + ld l, a + ld de, table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl ; address to jump to + exx + inc hl + ret ; jp (sp) => jump to table[a - 1] + +table: + LOCAL __01_decode_string + LOCAL __02_decode_byte + LOCAL __03_decode_ubyte + LOCAL __04_decode_integer + LOCAL __05_decode_uinteger + LOCAL __06_decode_long + LOCAL __07_decode_ulong + LOCAL __08_decode_fixed + LOCAL __09_decode_float + + ;; 1 -> Decode string + ;; 2, 3 -> Decode Byte, UByte + ;; 4, 5 -> Decode Integer, UInteger + ;; 6, 7 -> Decode Long, ULong + ;; 8 -> Decode Fixed + ;; 9 -> Decode Float + dw __01_decode_string + dw __02_decode_byte + dw __03_decode_ubyte + dw __04_decode_integer + dw __05_decode_uinteger + dw __06_decode_long + dw __07_decode_ulong + dw __08_decode_fixed + dw __09_decode_float + +__01_decode_string: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl + jp __LOADSTR + +__02_decode_byte: +__03_decode_ubyte: + ld a, (hl) + inc hl + ld (__DATA_ADDR), hl + ret + +__04_decode_integer: +__05_decode_uinteger: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl + ex de, hl + ret + +__06_decode_long: +__07_decode_ulong: +__08_decode_fixed: + ld b, h + ld c, l + inc bc + inc bc + inc bc + inc bc + ld (__DATA_ADDR), bc + jp __ILOAD32 + +__09_decode_float: + call __LOADF + inc hl + ld (__DATA_ADDR), hl + ld h, a ; returns A in H; sets A free + ret + +__DATA_ADDR: ;; Stores current DATA ptr + dw __DATA__0 + ENDP + + + + + + + + + + +#line 56 "read12.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 00 +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/read12.bas b/tests/functional/read12.bas new file mode 100644 index 000000000..0435712a6 --- /dev/null +++ b/tests/functional/read12.bas @@ -0,0 +1,14 @@ + +RESTORE test + +DIM a as Byte + +READ a +print a +read a +print a + + DATA "hola" + +test: DATA 1, 2 + diff --git a/tests/functional/read4.asm b/tests/functional/read4.asm new file mode 100644 index 000000000..739fa8879 --- /dev/null +++ b/tests/functional/read4.asm @@ -0,0 +1,1630 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld hl, __DATA__0 + call __RESTORE + ld hl, _v + 4 + call __FP_PUSH_REV + ld a, 082h + ld de, 00040h + ld bc, 00000h + call __MULF + ld hl, _x + 13 + call __STOREF + ld a, 9 + call __READ + ld hl, _x + 13 + call __STOREF + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +___DATA__FUNCPTR__0: + ld a, (_v) + ld de, (_v + 1) + ld bc, (_v + 3) + ld hl, 00000h + push hl + ld hl, 00048h + push hl + ld h, 085h + push hl + call __MULF + jp ___DATA__FUNCPTR__0__leave +___DATA__FUNCPTR__0__leave: + ret +___DATA__FUNCPTR__1: + ld a, (_v) + ld de, (_v + 1) + ld bc, (_v + 3) + call SIN + push bc + push de + push af + ld a, (_v) + ld de, (_v + 1) + ld bc, (_v + 3) + call TAN + push bc + push de + push af + ld a, 082h + ld de, 00000h + ld bc, 00000h + call __POW + call __MULF + jp ___DATA__FUNCPTR__1__leave +___DATA__FUNCPTR__1__leave: + ret +___DATA__FUNCPTR__2: + ld hl, __LABEL0 + call __LOADSTR + jp ___DATA__FUNCPTR__2__leave +___DATA__FUNCPTR__2__leave: + ret +__DATA__0: + DEFB 3 + DEFB 10 + DEFB 89h + DEFW ___DATA__FUNCPTR__0 + DEFB 89h + DEFW ___DATA__FUNCPTR__1 + DEFB 81h + DEFW ___DATA__FUNCPTR__2 +__DATA__END: + DEFB 00h +__LABEL0: + DEFW 0005h + DEFB 48h + DEFB 65h + DEFB 6Ch + DEFB 6Ch + DEFB 6Fh +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 69 "alloc.asm" +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 70 "alloc.asm" + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 93 "read4.bas" +#line 1 "mulf.asm" + +#line 1 "stackf.asm" + + ; ------------------------------------------------------------- + ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC + ; ------------------------------------------------------------- + + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) + __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) + +__FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) + ; Second argument to push into the stack calculator is popped out of the stack + ; Since the caller routine also receives the parameters into the top of the stack + ; four bytes must be removed from SP before pop them out + + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK + exx + pop hl ; Caller-Caller return addr + exx + pop hl ; Caller return addr + + pop af + pop de + pop bc + + push hl ; Caller return addr + exx + push hl ; Caller-Caller return addr + exx + + jp __FPSTACK_PUSH + + +__FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK + ; This format is specified in the ZX 48K Manual + ; You can push a 16 bit signed integer as + ; 0 SS LL HH 0, being SS the sign and LL HH the low + ; and High byte respectively + ld a, h + rla ; sign to Carry + sbc a, a ; 0 if positive, FF if negative + ld e, a + ld d, l + ld c, h + xor a + ld b, a + jp __FPSTACK_PUSH +#line 2 "mulf.asm" + + ; ------------------------------------------------------------- + ; Floating point library using the FP ROM Calculator (ZX 48K) + ; All of them uses A EDCB registers as 1st paramter. + ; For binary operators, the 2n operator must be pushed into the + ; stack, in the order A DE BC. + ; + ; Uses CALLEE convention + ; ------------------------------------------------------------- + +__MULF: ; Multiplication + call __FPSTACK_PUSH2 + + ; ------------- ROM MUL + rst 28h + defb 04h ; + defb 38h; ; END CALC + + jp __FPSTACK_POP + +#line 94 "read4.bas" +#line 1 "pow.asm" + + + + ; ------------------------------------------------------------- + ; Floating point library using the FP ROM Calculator (ZX 48K) + + ; All of them uses A EDCB registers as 1st paramter. + ; For binary operators, the 2n operator must be pushed into the + ; stack, in the order A DE BC. + ; + ; Uses CALLEE convention + ; +; Operands comes swapped: + ; 1 st parameter is the BASE (A ED CB) + ; 2 nd parameter (Top of the stack) is Exponent + ; ------------------------------------------------------------- + +__POW: ; Exponentiation + PROC + + call __FPSTACK_PUSH2 + + ; ------------- ROM POW + rst 28h + defb 01h ; Exchange => 1, Base + defb 06h ; POW + defb 38h; ; END CALC + + jp __FPSTACK_POP + + ENDP + +#line 95 "read4.bas" +#line 1 "pushf.asm" + + + ; Routine to push Float pointed by HL + ; Into the stack. Notice that the hl points to the last + ; byte of the FP number. + ; Uses H'L' B'C' and D'E' to preserve ABCDEHL registers + +__FP_PUSH_REV: + push hl + exx + pop hl + pop bc ; Return Address + ld d, (hl) + dec hl + ld e, (hl) + dec hl + push de + ld d, (hl) + dec hl + ld e, (hl) + dec hl + push de + ld d, (hl) + push de + push bc ; Return Address + exx + ret + + +#line 96 "read4.bas" +#line 1 "read_restore.asm" + + ;; This implements READ & RESTORE functions + ;; Reads a new element from the DATA Address code + ;; Updates the DATA_ADDR read ptr for the next read + + ;; Data codification is 1 byte for type followed by data bytes + ;; Byte type is encoded as follows + +;; 00: End of data +;; 01: String +;; 02: Byte +;; 03: Ubyte +;; 04: Integer +;; 05: UInteger +;; 06: Long +;; 07: ULong +;; 08: Fixed +;; 09: Float + + ;; bit7 is set for a parameter-less function + ;; In that case, the next two bytes are the ptr of the function to jump + + + +#line 1 "iload32.asm" + + ; __FASTCALL__ routine which + ; loads a 32 bits integer into DE,HL + ; stored at position pointed by POINTER HL + ; DE,HL <-- (HL) + +__ILOAD32: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + ex de, hl + ret + +#line 25 "read_restore.asm" +#line 1 "iloadf.asm" + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- ((HL)) + +__ILOADF: + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- (HL) + +__LOADF: ; Loads a 40 bits FP number from address pointed by HL + ld a, (hl) + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld c, (hl) + inc hl + ld b, (hl) + ret + +#line 26 "read_restore.asm" +#line 1 "ftof16reg.asm" + +#line 1 "ftou32reg.asm" + +#line 1 "neg32.asm" + +__ABS32: + bit 7, d + ret z + +__NEG32: ; Negates DEHL (Two's complement) + ld a, l + cpl + ld l, a + + ld a, h + cpl + ld h, a + + ld a, e + cpl + ld e, a + + ld a, d + cpl + ld d, a + + inc l + ret nz + + inc h + ret nz + + inc de + ret + +#line 2 "ftou32reg.asm" + +__FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + ; Output: DEHL 32 bit number (signed) + PROC + + LOCAL __IS_FLOAT + + or a + jr nz, __IS_FLOAT + ; Here if it is a ZX ROM Integer + + ld h, c + ld l, d + ld a, e ; Takes sign: FF = -, 0 = + + ld de, 0 + inc a + jp z, __NEG32 ; Negates if negative + ret + +__IS_FLOAT: ; Jumps here if it is a true floating point number + ld h, e + push hl ; Stores it for later (Contains Sign in H) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + ;ld a, c ; Get exponent + sub 128 ; Exponent -= 128 + jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + +__FTOU32REG_LOOP: + exx ; Shift C'B' E'D' << 1, output bit stays in Carry + sla d + rl e + rl b + rl c + + exx ; Shift DEHL << 1, inserting the carry on the right + rl l + rl h + rl e + rl d + + djnz __FTOU32REG_LOOP + +__FTOU32REG_END: + pop af ; Take the sign bit + or a ; Sets SGN bit to 1 if negative + jp m, __NEG32 ; Negates DEHL + + ret + + ENDP + + +__FTOU8: ; Converts float in C ED LH to Unsigned byte in A + call __FTOU32REG + ld a, l + ret + +#line 2 "ftof16reg.asm" + +__FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + + ld l, a ; Saves exponent for later + or d + or e + or b + or c + ld h, e + ret z ; Return if ZERO + + push hl ; Stores it for later (Contains sign in H, exponent in L) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + pop bc + + ld a, c ; Get exponent + sub 112 ; Exponent -= 128 + 16 + + push bc ; Saves sign in b again + + jp z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jp c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + 16 (we need to shift 16 bit more) + jp __FTOU32REG_LOOP ; proceed as an u32 integer + +#line 27 "read_restore.asm" +#line 1 "f16tofreg.asm" + + +#line 1 "u32tofreg.asm" + + +__I8TOFREG: + ld l, a + rlca + sbc a, a ; A = SGN(A) + ld h, a + ld e, a + ld d, a + +__I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) + ; to a Floating Point Number returned in (A ED CB) + + ld a, d + or a ; Test sign + + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __U32TOFREG ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + +__U8TOFREG: + ; Converts an unsigned 8 bit (A) to Floating point + ld l, a + ld h, 0 + ld e, h + ld d, h + +__U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in A ED CB + + PROC + + LOCAL __U32TOFREG_END + + ld a, d + or e + or h + or l + ld b, d + ld c, e ; Returns 00 0000 0000 if ZERO + ret z + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 128 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + +__U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG + exx + ld a, d ; B'C'D'E' == 0 ? + or e + or b + or c + jp z, __U32TOFREG_END ; We are done + + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry + rr c + rr d + rr e + exx + + rr e ; Shift EDCB >> 1, inserting the carry on the left + rr d + rr c + rr b + + inc l ; Increment exponent + jp __U32TOFREG_LOOP + + +__U32TOFREG_END: + exx + ld a, l ; Puts the exponent in a + res 7, e ; Sets the sign bit to 0 (positive) + + ret + ENDP + +#line 3 "f16tofreg.asm" + +__F16TOFREG: ; Converts a 16.16 signed fixed point (stored in DEHL) + ; to a Floating Point Number returned in (C ED CB) + PROC + + LOCAL __F16TOFREG2 + + ld a, d + or a ; Test sign + + jp p, __F16TOFREG2 ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __F16TOFREG2 ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + + +__F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in C DE HL + + ld a, d + or e + or h + or l + ld b, h + ld c, l + ret z ; Return 00 0000 0000 if 0 + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 112 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + jp __U32TOFREG_LOOP ; Proceed as an integer + + ENDP + +#line 28 "read_restore.asm" +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 29 "read_restore.asm" + + + + + + + + + + + + + ;; Updates restore point to the given HL mem. address +__RESTORE: + PROC + LOCAL __DATA_ADDR + + ld (__DATA_ADDR), hl + ret + + ;; Reads a value from the DATA mem area and updates __DATA_ADDR ptr to the + ;; next item. On Out Of Data, restarts + ;; +__READ: + LOCAL read_restart, cont, cont2, table, no_func + LOCAL dynamic_cast, dynamic_cast2, dynamic_cast3, dynamic_cast4 + LOCAL _decode_table, coerce_to_int, coerce_to_int2, promote_to_i16 + LOCAL _from_i8, _from_u8 + LOCAL _from_i16, _from_u16 + LOCAL _from_i32, _from_u32 + LOCAL _from_fixed, __data_error + + push af ; type of data to read + ld hl, (__DATA_ADDR) +read_restart: + ld a, (hl) + or a ; 0 => OUT of data + jr nz, cont + ;; Signals out of data + + ld hl, __DATA__0 + ld (__DATA_ADDR), hl + jr read_restart ; Start again +cont: + and 0x80 + ld a, (hl) + push af + jp z, no_func ;; Loads data directly, not a function + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl +cont2: + ld de, dynamic_cast + push de ; ret address + jp (hl) ; "call (hl)" + + ;; Now tries to convert the given result to the expected type or raise an error +dynamic_cast: + exx + ex af, af' + pop af ; type READ + and 0x7F ; clear bit 7 + pop hl ; type requested by USER (type of the READ variable) + ld c, h ; save requested type (save it in register C) + cp h + exx + jr nz, dynamic_cast2 ; Types are identical? + ;; yes, they are + ex af, af' + ret + +dynamic_cast2: + cp 1 ; Requested a number, but read a string? + jr nz, dynamic_cast3 + call __MEM_FREE ; Frees str from memory + jr __data_error + +dynamic_cast3: + exx + ld b, a ; Read type + ld a, c ; Requested type + cp 1 + jr z, __data_error + cp b + jr c, dynamic_cast4 + ;; here the user expected type is "larger" than the read one + ld a, b + sub 2 + add a, a + ld l, a + ld h, 0 + ld de, _decode_table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl + ld a, c ; Requested type + exx + ret + +__data_error: + ;; When a data is read, but cannot be converted to the requested type + ;; that is, the user asked for a string and we read a number or vice versa + ld a, ERROR_InvalidArg + call __STOP ; The user expected a string, but read a number + xor a + ld h, a + ld l, a + ld e, a + ld d, a + ld b, a + ld c, a + ret + +_decode_table: + dw _from_i8 + dw _from_u8 + dw _from_i16 + dw _from_u16 + dw _from_i32 + dw _from_u32 + dw _from_fixed + +_from_i8: + cp 4 + jr nc, promote_to_i16 + ex af, af' + ret ;; Was from Byte to Ubyte + +promote_to_i16: + ex af, af' + ld l, a + rla + sbc a, a + ld h, a ; copy sgn to h + ex af, af' + jr _before_from_i16 + +_from_u8: + ex af, af' + ld l, a + ld h, 0 + ex af, af' + ;; Promoted to i16 + +_before_from_i16: +_from_i16: + cp 6 + ret c ;; from i16 to u16 + ;; Promote i16 to i32 + ex af, af' + ld a, h + rla + sbc a, a + ld e, a + ld d, a + ex af, af' +_from_i32: + cp 7 + ret z ;; From i32 to u32 + ret c ;; From u16 to i32 + cp 9 + jp z, __I32TOFREG +_from_u32: + cp 9 + jp z, __U32TOFREG + ex de, hl + ld hl, 0 + cp 8 + ret z +_from_fixed: ;; From fixed to float + jp __F16TOFREG +_from_u16: + ld de, 0 ; HL 0x0000 => 32 bits + jp _from_i32 + +dynamic_cast4: + ;; The user type is "shorter" than the read one + cp 8 ;; required type + jr c, before_to_int ;; required < fixed (f16) + ex af, af' + exx ;; Ok, we must convert from float to f16 + jp __FTOF16REG + +before_to_int: + ld a, b ;; read type + cp 8 ;; + jr nz, coerce_to_int ;; From float to int + ld a, c ;; user type + exx + ;; f16 to Long + ex de, hl + ld a, h + rla + sbc a, a + ld d, a + ld e, a + exx + jr coerce_to_int2 +coerce_to_int: + exx + ex af, af' + call __FTOU32REG + ex af, af' ; a contains user type + exx +coerce_to_int2: ; At this point we have an u/integer in hl + exx + cp 4 + ret nc ; Already done. Return the result + ld a, l ; Truncate to byte + ret + +no_func: + exx + ld de, dynamic_cast + push de ; Ret address + dec a ; 0 => string; 1, 2 => byte; 3, 4 => integer; 5, 6 => long, 7 => fixed; 8 => float + ld h, 0 + add a, a + ld l, a + ld de, table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl ; address to jump to + exx + inc hl + ret ; jp (sp) => jump to table[a - 1] + +table: + LOCAL __01_decode_string + LOCAL __02_decode_byte + LOCAL __03_decode_ubyte + LOCAL __04_decode_integer + LOCAL __05_decode_uinteger + LOCAL __06_decode_long + LOCAL __07_decode_ulong + LOCAL __08_decode_fixed + LOCAL __09_decode_float + + ;; 1 -> Decode string + ;; 2, 3 -> Decode Byte, UByte + ;; 4, 5 -> Decode Integer, UInteger + ;; 6, 7 -> Decode Long, ULong + ;; 8 -> Decode Fixed + ;; 9 -> Decode Float + dw __01_decode_string + dw __02_decode_byte + dw __03_decode_ubyte + dw __04_decode_integer + dw __05_decode_uinteger + dw __06_decode_long + dw __07_decode_ulong + dw __08_decode_fixed + dw __09_decode_float + +__01_decode_string: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl + jp __LOADSTR + +__02_decode_byte: +__03_decode_ubyte: + ld a, (hl) + inc hl + ld (__DATA_ADDR), hl + ret + +__04_decode_integer: +__05_decode_uinteger: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl + ex de, hl + ret + +__06_decode_long: +__07_decode_ulong: +__08_decode_fixed: + ld b, h + ld c, l + inc bc + inc bc + inc bc + inc bc + ld (__DATA_ADDR), bc + jp __ILOAD32 + +__09_decode_float: + call __LOADF + inc hl + ld (__DATA_ADDR), hl + ld h, a ; returns A in H; sets A free + ret + +__DATA_ADDR: ;; Stores current DATA ptr + dw __DATA__0 + ENDP + + + + + + + + + + +#line 97 "read4.bas" +#line 1 "sin.asm" + + + +SIN: ; Computes SIN using ROM FP-CALC + call __FPSTACK_PUSH + + rst 28h ; ROM CALC + defb 1Fh + defb 38h ; END CALC + + jp __FPSTACK_POP + +#line 98 "read4.bas" +#line 1 "storef.asm" + +__PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) + push de + ex de, hl ; DE <- HL + push ix + pop hl ; HL <- IX + add hl, de ; HL <- IX + HL + pop de + +__ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register + ex af, af' + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex af, af' + +__STOREF: ; Stores the given FP number in A EDCB at address HL + ld (hl), a + inc hl + ld (hl), e + inc hl + ld (hl), d + inc hl + ld (hl), c + inc hl + ld (hl), b + ret + +#line 99 "read4.bas" +#line 1 "tan.asm" + + + +TAN: ; Computes TAN using ROM FP-CALC + call __FPSTACK_PUSH + + rst 28h ; ROM CALC + defb 21h ; TAN + defb 38h ; END CALC + + jp __FPSTACK_POP + +#line 100 "read4.bas" + +ZXBASIC_USER_DATA: +_v: + DEFB 81h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h +_x: + DEFW 0000h + DEFB 05h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/read4.bas b/tests/functional/read4.bas new file mode 100644 index 000000000..d4b2f44ab --- /dev/null +++ b/tests/functional/read4.bas @@ -0,0 +1,15 @@ +REM Error x is an array, not an scalar + +DIM v as Float = 1 + +RESTORE + +DATA 10, 25 * v, SIN(v) * tan(v)^2, "Hello" + + +DIM x(4) as Float +LET x(2) = v * 3 +READ x(2) + + + diff --git a/tests/functional/read5.asm b/tests/functional/read5.asm new file mode 100644 index 000000000..1b18c152f --- /dev/null +++ b/tests/functional/read5.asm @@ -0,0 +1,2784 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + call __PRINT_INIT + ld hl, __DATA__0 + call __RESTORE + ld a, 1 + ld (_i), a + jp __LABEL0 +__LABEL3: + ld a, 9 + call __READ + ld hl, _c + call __STOREF + ld a, 9 + call __READ + ld hl, _d + call __STOREF + ld a, (_c) + ld de, (_c + 1) + ld bc, (_c + 3) + call __PRINTF + call PRINT_COMMA + ld a, (_d) + ld de, (_d + 1) + ld bc, (_d + 3) + call __PRINTF + call PRINT_EOL +__LABEL4: + ld a, (_i) + inc a + ld (_i), a +__LABEL0: + ld a, 4 + ld hl, (_i - 1) + cp h + jp nc, __LABEL3 +__LABEL2: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +___DATA__FUNCPTR__0: + ld a, (_v) + ld de, (_v + 1) + ld bc, (_v + 3) + ld hl, 00000h + push hl + ld hl, 00048h + push hl + ld h, 085h + push hl + call __MULF + jp ___DATA__FUNCPTR__0__leave +___DATA__FUNCPTR__0__leave: + ret +___DATA__FUNCPTR__1: + ld a, (_v) + ld de, (_v + 1) + ld bc, (_v + 3) + call SIN + push bc + push de + push af + ld a, (_v) + ld de, (_v + 1) + ld bc, (_v + 3) + call TAN + push bc + push de + push af + ld a, 082h + ld de, 00000h + ld bc, 00000h + call __POW + call __MULF + jp ___DATA__FUNCPTR__1__leave +___DATA__FUNCPTR__1__leave: + ret +___DATA__FUNCPTR__2: + ld a, (_v) + ld de, (_v + 1) + ld bc, (_v + 3) + ld hl, 0A2DAh + push hl + ld hl, 00F49h + push hl + ld h, 082h + push hl + call __MULF + jp ___DATA__FUNCPTR__2__leave +___DATA__FUNCPTR__2__leave: + ret +__DATA__0: + DEFB 3 + DEFB 10 + DEFB 89h + DEFW ___DATA__FUNCPTR__0 + DEFB 89h + DEFW ___DATA__FUNCPTR__1 + DEFB 89h + DEFW ___DATA__FUNCPTR__2 +__DATA__END: + DEFB 00h +#line 1 "mulf.asm" + +#line 1 "stackf.asm" + + ; ------------------------------------------------------------- + ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC + ; ------------------------------------------------------------- + + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) + __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) + +__FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) + ; Second argument to push into the stack calculator is popped out of the stack + ; Since the caller routine also receives the parameters into the top of the stack + ; four bytes must be removed from SP before pop them out + + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK + exx + pop hl ; Caller-Caller return addr + exx + pop hl ; Caller return addr + + pop af + pop de + pop bc + + push hl ; Caller return addr + exx + push hl ; Caller-Caller return addr + exx + + jp __FPSTACK_PUSH + + +__FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK + ; This format is specified in the ZX 48K Manual + ; You can push a 16 bit signed integer as + ; 0 SS LL HH 0, being SS the sign and LL HH the low + ; and High byte respectively + ld a, h + rla ; sign to Carry + sbc a, a ; 0 if positive, FF if negative + ld e, a + ld d, l + ld c, h + xor a + ld b, a + jp __FPSTACK_PUSH +#line 2 "mulf.asm" + + ; ------------------------------------------------------------- + ; Floating point library using the FP ROM Calculator (ZX 48K) + ; All of them uses A EDCB registers as 1st paramter. + ; For binary operators, the 2n operator must be pushed into the + ; stack, in the order A DE BC. + ; + ; Uses CALLEE convention + ; ------------------------------------------------------------- + +__MULF: ; Multiplication + call __FPSTACK_PUSH2 + + ; ------------- ROM MUL + rst 28h + defb 04h ; + defb 38h; ; END CALC + + jp __FPSTACK_POP + +#line 114 "read5.bas" +#line 1 "pow.asm" + + + + ; ------------------------------------------------------------- + ; Floating point library using the FP ROM Calculator (ZX 48K) + + ; All of them uses A EDCB registers as 1st paramter. + ; For binary operators, the 2n operator must be pushed into the + ; stack, in the order A DE BC. + ; + ; Uses CALLEE convention + ; +; Operands comes swapped: + ; 1 st parameter is the BASE (A ED CB) + ; 2 nd parameter (Top of the stack) is Exponent + ; ------------------------------------------------------------- + +__POW: ; Exponentiation + PROC + + call __FPSTACK_PUSH2 + + ; ------------- ROM POW + rst 28h + defb 01h ; Exchange => 1, Base + defb 06h ; POW + defb 38h; ; END CALC + + jp __FPSTACK_POP + + ENDP + +#line 115 "read5.bas" +#line 1 "print.asm" + +; vim:ts=4:sw=4:et: + ; PRINT command routine + ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that + +#line 1 "sposn.asm" + + ; Printing positioning library. + PROC + LOCAL ECHO_E + +__LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. + ld de, (S_POSN) + ld hl, (MAXX) + or a + sbc hl, de + ex de, hl + ret + + +__SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. + ld hl, (MAXX) + or a + sbc hl, de + ld (S_POSN), hl ; saves it again + ret + + + ECHO_E EQU 23682 + MAXX EQU ECHO_E ; Max X position + 1 + MAXY EQU MAXX + 1 ; Max Y position + 1 + + S_POSN EQU 23688 + POSX EQU S_POSN ; Current POS X + POSY EQU S_POSN + 1 ; Current POS Y + + ENDP + +#line 6 "print.asm" +#line 1 "cls.asm" + + ; JUMPS directly to spectrum CLS + ; This routine does not clear lower screen + + ;CLS EQU 0DAFh + + ; Our faster implementation + + + +CLS: + PROC + + LOCAL COORDS + LOCAL __CLS_SCR + LOCAL ATTR_P + LOCAL SCREEN + + ld hl, 0 + ld (COORDS), hl + ld hl, 1821h + ld (S_POSN), hl +__CLS_SCR: + ld hl, SCREEN + ld (hl), 0 + ld d, h + ld e, l + inc de + ld bc, 6144 + ldir + + ; Now clear attributes + + ld a, (ATTR_P) + ld (hl), a + ld bc, 767 + ldir + ret + + COORDS EQU 23677 + SCREEN EQU 16384 ; Default start of the screen (can be changed) + ATTR_P EQU 23693 + ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address + + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines + ; to get the start of the screen + ENDP + +#line 7 "print.asm" +#line 1 "in_screen.asm" + + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 3 "in_screen.asm" + +__IN_SCREEN: + ; Returns NO carry if current coords (D, E) + ; are OUT of the screen limits (MAXX, MAXY) + + PROC + LOCAL __IN_SCREEN_ERR + + ld hl, MAXX + ld a, e + cp (hl) + jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + + ld a, d + inc hl + cp (hl) + ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + ;; ret + ret c ; Return if carry (OK) + +__IN_SCREEN_ERR: +__OUT_OF_SCREEN_ERR: + ; Jumps here if out of screen + ld a, ERROR_OutOfScreen + jp __STOP ; Saves error code and exits + + ENDP +#line 8 "print.asm" +#line 1 "table_jump.asm" + + +JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A + add a, a + +JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE + ld e, a + ld d, 0 + +JUMP_HL_PLUS_DE: ; Does JP (HL + DE) + add hl, de + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl +CALL_HL: + jp (hl) + +#line 9 "print.asm" +#line 1 "ink.asm" + + ; Sets ink color in ATTR_P permanently +; Parameter: Paper color in A register + +#line 1 "const.asm" + + ; Global constants + + P_FLAG EQU 23697 + FLAGS2 EQU 23681 + ATTR_P EQU 23693 ; permanet ATTRIBUTES + ATTR_T EQU 23695 ; temporary ATTRIBUTES + CHARS EQU 23606 ; Pointer to ROM/RAM Charset + UDG EQU 23675 ; Pointer to UDG Charset + MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars + +#line 5 "ink.asm" + +INK: + PROC + LOCAL __SET_INK + LOCAL __SET_INK2 + + ld de, ATTR_P + +__SET_INK: + cp 8 + jr nz, __SET_INK2 + + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + or 7 ; Set bits 0,1,2 to enable transparency + ld (de), a + ret + +__SET_INK2: + ; Another entry. This will set the ink color at location pointer by DE + and 7 ; # Gets color mod 8 + ld b, a ; Saves the color + ld a, (de) + and 0F8h ; Clears previous value + or b + ld (de), a + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + and 0F8h ; Reset bits 0,1,2 sign to disable transparency + ld (de), a ; Store new attr + ret + + ; Sets the INK color passed in A register in the ATTR_T variable +INK_TMP: + ld de, ATTR_T + jp __SET_INK + + ENDP + +#line 10 "print.asm" +#line 1 "paper.asm" + + ; Sets paper color in ATTR_P permanently +; Parameter: Paper color in A register + + + +PAPER: + PROC + LOCAL __SET_PAPER + LOCAL __SET_PAPER2 + + ld de, ATTR_P + +__SET_PAPER: + cp 8 + jr nz, __SET_PAPER2 + inc de + ld a, (de) + or 038h + ld (de), a + ret + + ; Another entry. This will set the paper color at location pointer by DE +__SET_PAPER2: + and 7 ; # Remove + rlca + rlca + rlca ; a *= 8 + + ld b, a ; Saves the color + ld a, (de) + and 0C7h ; Clears previous value + or b + ld (de), a + inc de ; Points to MASK_T or MASK_P accordingly + ld a, (de) + and 0C7h ; Resets bits 3,4,5 + ld (de), a + ret + + + ; Sets the PAPER color passed in A register in the ATTR_T variable +PAPER_TMP: + ld de, ATTR_T + jp __SET_PAPER + ENDP + +#line 11 "print.asm" +#line 1 "flash.asm" + + ; Sets flash flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +FLASH: + ld de, ATTR_P +__SET_FLASH: + ; Another entry. This will set the flash flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + ld b, a ; Saves the color + ld a, (de) + and 07Fh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the FLASH flag passed in A register in the ATTR_T variable +FLASH_TMP: + ld de, ATTR_T + jr __SET_FLASH + +#line 12 "print.asm" +#line 1 "bright.asm" + + ; Sets bright flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +BRIGHT: + ld de, ATTR_P + +__SET_BRIGHT: + ; Another entry. This will set the bright flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + rrca + ld b, a ; Saves the color + ld a, (de) + and 0BFh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable +BRIGHT_TMP: + ld de, ATTR_T + jr __SET_BRIGHT + +#line 13 "print.asm" +#line 1 "over.asm" + + ; Sets OVER flag in P_FLAG permanently +; Parameter: OVER flag in bit 0 of A register +#line 1 "copy_attr.asm" + + + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" + + + +COPY_ATTR: + ; Just copies current permanent attribs to temporal attribs + ; and sets print mode + PROC + + LOCAL INVERSE1 + LOCAL __REFRESH_TMP + + INVERSE1 EQU 02Fh + + ld hl, (ATTR_P) + ld (ATTR_T), hl + + ld hl, FLAGS2 + call __REFRESH_TMP + + ld hl, P_FLAG + call __REFRESH_TMP + + +__SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) + + + LOCAL TABLE + LOCAL CONT2 + + rra ; Over bit to carry + ld a, (FLAGS2) + rla ; Over bit in bit 1, Over2 bit in bit 2 + and 3 ; Only bit 0 and 1 (OVER flag) + + ld c, a + ld b, 0 + + ld hl, TABLE + add hl, bc + ld a, (hl) + ld (PRINT_MODE), a + + ld hl, (P_FLAG) + xor a ; NOP -> INVERSE0 + bit 2, l + jr z, CONT2 + ld a, INVERSE1 ; CPL -> INVERSE1 + +CONT2: + ld (INVERSE_MODE), a + ret + +TABLE: + nop ; NORMAL MODE + xor (hl) ; OVER 1 MODE + and (hl) ; OVER 2 MODE + or (hl) ; OVER 3 MODE + +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" + +__REFRESH_TMP: + ld a, (hl) + and 10101010b + ld c, a + rra + or c + ld (hl), a + ret + + ENDP + +#line 4 "over.asm" + + +OVER: + PROC + + ld c, a ; saves it for later + and 2 + ld hl, FLAGS2 + res 1, (HL) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 ; # Convert to 0/1 + add a, a; # Shift left 1 bit for permanent + + ld hl, P_FLAG + res 1, (hl) + or (hl) + ld (hl), a + ret + + ; Sets OVER flag in P_FLAG temporarily +OVER_TMP: + ld c, a ; saves it for later + and 2 ; gets bit 1; clears carry + rra + ld hl, FLAGS2 + res 0, (hl) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 + ld hl, P_FLAG + res 0, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 14 "print.asm" +#line 1 "inverse.asm" + + ; Sets INVERSE flag in P_FLAG permanently +; Parameter: INVERSE flag in bit 0 of A register + + + +INVERSE: + PROC + + and 1 ; # Convert to 0/1 + add a, a; # Shift left 3 bits for permanent + add a, a + add a, a + ld hl, P_FLAG + res 3, (hl) + or (hl) + ld (hl), a + ret + + ; Sets INVERSE flag in P_FLAG temporarily +INVERSE_TMP: + and 1 + add a, a + add a, a; # Shift left 2 bits for temporary + ld hl, P_FLAG + res 2, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 15 "print.asm" +#line 1 "bold.asm" + + ; Sets BOLD flag in P_FLAG permanently +; Parameter: BOLD flag in bit 0 of A register + + +BOLD: + PROC + + and 1 + rlca + rlca + rlca + ld hl, FLAGS2 + res 3, (HL) + or (hl) + ld (hl), a + ret + + ; Sets BOLD flag in P_FLAG temporarily +BOLD_TMP: + and 1 + rlca + rlca + ld hl, FLAGS2 + res 2, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 16 "print.asm" +#line 1 "italic.asm" + + ; Sets ITALIC flag in P_FLAG permanently +; Parameter: ITALIC flag in bit 0 of A register + + +ITALIC: + PROC + + and 1 + rrca + rrca + rrca + ld hl, FLAGS2 + res 5, (HL) + or (hl) + ld (hl), a + ret + + ; Sets ITALIC flag in P_FLAG temporarily +ITALIC_TMP: + and 1 + rrca + rrca + rrca + rrca + ld hl, FLAGS2 + res 4, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 17 "print.asm" + +#line 1 "attr.asm" + + ; Attribute routines +; vim:ts=4:et:sw: + + + + + + + +__ATTR_ADDR: + ; calc start address in DE (as (32 * d) + e) + ; Contributed by Santiago Romero at http://www.speccy.org + ld h, 0 ; 7 T-States + ld a, d ; 4 T-States + add a, a ; a * 2 ; 4 T-States + add a, a ; a * 4 ; 4 T-States + ld l, a ; HL = A * 4 ; 4 T-States + + add hl, hl ; HL = A * 8 ; 15 T-States + add hl, hl ; HL = A * 16 ; 15 T-States + add hl, hl ; HL = A * 32 ; 15 T-States + + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) + add hl, de + + ld de, (SCREEN_ADDR) ; Adds the screen address + add hl, de + + ; Return current screen address in HL + ret + + + ; Sets the attribute at a given screen coordinate (D, E). + ; The attribute is taken from the ATTR_T memory variable + ; Used by PRINT routines +SET_ATTR: + + ; Checks for valid coords + call __IN_SCREEN + ret nc + +__SET_ATTR: + ; Internal __FASTCALL__ Entry used by printing routines + PROC + + call __ATTR_ADDR + ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T + + ld a, d + and (hl) + ld c, a ; C = current screen color, masked + + ld a, d + cpl ; Negate mask + and e ; Mask current attributes + or c ; Mix them + ld (hl), a ; Store result in screen + + ret + + ENDP + + +#line 19 "print.asm" + + ; Putting a comment starting with @INIT
+ ; will make the compiler to add a CALL to
+ ; It is useful for initialization routines. + + +__PRINT_INIT: ; To be called before program starts (initializes library) + PROC + + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + + ld hl, 1821h + ld (MAXX), hl ; Sets current maxX and maxY + + xor a + ld (FLAGS2), a + + ret + + +__PRINTCHAR: ; Print character store in accumulator (A register) + ; Modifies H'L', B'C', A'F', D'E', A + + LOCAL PO_GR_1 + + LOCAL __PRCHAR + LOCAL __PRINT_CONT + LOCAL __PRINT_CONT2 + LOCAL __PRINT_JUMP + LOCAL __SRCADDR + LOCAL __PRINT_UDG + LOCAL __PRGRAPH + LOCAL __PRINT_START + + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 + +__PRINT_JUMP: + jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively + +__PRINT_START: + cp ' ' + jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones + + exx ; Switch to alternative registers + ex af, af' ; Saves a value (char to print) for later + + call __LOAD_S_POSN + + ; At this point we have the new coord + ld hl, (SCREEN_ADDR) + + ld a, d + ld c, a ; Saves it for later + + and 0F8h ; Masks 3 lower bit ; zy + ld d, a + + ld a, c ; Recovers it + and 07h ; MOD 7 ; y1 + rrca + rrca + rrca + + or e + ld e, a + add hl, de ; HL = Screen address + DE + ex de, hl ; DE = Screen address + + ex af, af' + + cp 80h ; Is it an UDG or a ? + jp c, __SRCADDR + + cp 90h + jp nc, __PRINT_UDG + + ; Print a 8 bit pattern (80h to 8Fh) + + ld b, a + call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 + ld hl, MEM0 + jp __PRGRAPH + + PO_GR_1 EQU 0B38h + +__PRINT_UDG: + sub 90h ; Sub ASC code + ld bc, (UDG) + jp __PRGRAPH0 + + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source +__SRCADDR: + ld bc, (CHARS) + +__PRGRAPH0: + add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org + ld l, a + ld h, 0 ; HL = a * 2 (accumulator) + add hl, hl + add hl, hl ; HL = a * 8 + add hl, bc ; HL = CHARS address + +__PRGRAPH: + ex de, hl ; HL = Write Address, DE = CHARS address + bit 2, (iy + $47) + call nz, __BOLD + bit 4, (iy + $47) + call nz, __ITALIC + ld b, 8 ; 8 bytes per char +__PRCHAR: + ld a, (de) ; DE *must* be ALWAYS source, and HL destiny + +PRINT_MODE: ; Which operation is used to write on the screen + ; Set it with: + ; LD A, + ; LD (PRINT_MODE), A + ; + ; Available opertions: + ; NORMAL: 0h --> NOP ; OVER 0 + ; XOR : AEh --> XOR (HL) ; OVER 1 + ; OR : B6h --> OR (HL) ; PUTSPRITE + ; AND : A6h --> AND (HL) ; PUTMASK + nop ; + +INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 + nop ; 2F -> CPL -> INVERSE 1 + + ld (hl), a + + inc de + inc h ; Next line + djnz __PRCHAR + + call __LOAD_S_POSN + push de + call __SET_ATTR + pop de + inc e ; COL = COL + 1 + ld hl, (MAXX) + ld a, e + dec l ; l = MAXX + cp l ; Lower than max? + jp c, __PRINT_CONT; Nothing to do + call __PRINT_EOL1 + exx ; counteracts __PRINT_EOL1 exx + jp __PRINT_CONT2 + +__PRINT_CONT: + call __SAVE_S_POSN + +__PRINT_CONT2: + exx + ret + + ; ------------- SPECIAL CHARS (< 32) ----------------- + +__PRINT_SPECIAL: ; Jumps here if it is a special char + exx + ld hl, __PRINT_TABLE + jp JUMP_HL_PLUS_2A + + +PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence + exx + +__PRINT_0Dh: ; Called WHEN printing CHR$(13) + call __LOAD_S_POSN + +__PRINT_EOL1: ; Another entry called from PRINT when next line required + ld e, 0 + +__PRINT_EOL2: + ld a, d + inc a + +__PRINT_AT1_END: + ld hl, (MAXY) + cp l + jr c, __PRINT_EOL_END ; Carry if (MAXY) < d + xor a + +__PRINT_EOL_END: + ld d, a + +__PRINT_AT2_END: + call __SAVE_S_POSN + exx + ret + +__PRINT_COM: + exx + push hl + push de + push bc + call PRINT_COMMA + pop bc + pop de + pop hl + ret + +__PRINT_TAB: + ld hl, __PRINT_TAB1 + jp __PRINT_SET_STATE + +__PRINT_TAB1: + ld (MEM0), a + ld hl, __PRINT_TAB2 + ld (PRINT_JUMP_STATE), hl + ret + +__PRINT_TAB2: + ld a, (MEM0) ; Load tab code (ignore the current one) + push hl + push de + push bc + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + call PRINT_TAB + pop bc + pop de + pop hl + ret + +__PRINT_NOP: +__PRINT_RESTART: + ld hl, __PRINT_START + jp __PRINT_SET_STATE + +__PRINT_AT: + ld hl, __PRINT_AT1 + +__PRINT_SET_STATE: + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + exx + ret + +__PRINT_AT1: ; Jumps here if waiting for 1st parameter + exx + ld hl, __PRINT_AT2 + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + jp __PRINT_AT1_END + +__PRINT_AT2: + exx + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + ld e, a + ld hl, (MAXX) + cp (hl) + jr c, __PRINT_AT2_END + jr __PRINT_EOL1 + +__PRINT_DEL: + call __LOAD_S_POSN ; Gets current screen position + dec e + ld a, -1 + cp e + jp nz, __PRINT_AT2_END + ld hl, (MAXX) + ld e, l + dec e + dec e + dec d + cp d + jp nz, __PRINT_AT2_END + ld d, h + dec d + jp __PRINT_AT2_END + +__PRINT_INK: + ld hl, __PRINT_INK2 + jp __PRINT_SET_STATE + +__PRINT_INK2: + exx + call INK_TMP + jp __PRINT_RESTART + +__PRINT_PAP: + ld hl, __PRINT_PAP2 + jp __PRINT_SET_STATE + +__PRINT_PAP2: + exx + call PAPER_TMP + jp __PRINT_RESTART + +__PRINT_FLA: + ld hl, __PRINT_FLA2 + jp __PRINT_SET_STATE + +__PRINT_FLA2: + exx + call FLASH_TMP + jp __PRINT_RESTART + +__PRINT_BRI: + ld hl, __PRINT_BRI2 + jp __PRINT_SET_STATE + +__PRINT_BRI2: + exx + call BRIGHT_TMP + jp __PRINT_RESTART + +__PRINT_INV: + ld hl, __PRINT_INV2 + jp __PRINT_SET_STATE + +__PRINT_INV2: + exx + call INVERSE_TMP + jp __PRINT_RESTART + +__PRINT_OVR: + ld hl, __PRINT_OVR2 + jp __PRINT_SET_STATE + +__PRINT_OVR2: + exx + call OVER_TMP + jp __PRINT_RESTART + +__PRINT_BOLD: + ld hl, __PRINT_BOLD2 + jp __PRINT_SET_STATE + +__PRINT_BOLD2: + exx + call BOLD_TMP + jp __PRINT_RESTART + +__PRINT_ITA: + ld hl, __PRINT_ITA2 + jp __PRINT_SET_STATE + +__PRINT_ITA2: + exx + call ITALIC_TMP + jp __PRINT_RESTART + + +__BOLD: + push hl + ld hl, MEM0 + ld b, 8 +__BOLD_LOOP: + ld a, (de) + ld c, a + rlca + or c + ld (hl), a + inc hl + inc de + djnz __BOLD_LOOP + pop hl + ld de, MEM0 + ret + + +__ITALIC: + push hl + ld hl, MEM0 + ex de, hl + ld bc, 8 + ldir + ld hl, MEM0 + srl (hl) + inc hl + srl (hl) + inc hl + srl (hl) + inc hl + inc hl + inc hl + sla (hl) + inc hl + sla (hl) + inc hl + sla (hl) + pop hl + ld de, MEM0 + ret + +PRINT_COMMA: + call __LOAD_S_POSN + ld a, e + and 16 + add a, 16 + +PRINT_TAB: + PROC + LOCAL LOOP, CONTINUE + + inc a + call __LOAD_S_POSN ; e = current row + ld d, a + ld a, e + cp 21h + jr nz, CONTINUE + ld e, -1 +CONTINUE: + ld a, d + inc e + sub e ; A = A - E + and 31 ; + ret z ; Already at position E + ld b, a +LOOP: + ld a, ' ' + call __PRINTCHAR + djnz LOOP + ret + ENDP + +PRINT_AT: ; CHanges cursor to ROW, COL + ; COL in A register + ; ROW in stack + + pop hl ; Ret address + ex (sp), hl ; callee H = ROW + ld l, a + ex de, hl + + call __IN_SCREEN + ret nc ; Return if out of screen + + jp __SAVE_S_POSN + + LOCAL __PRINT_COM + LOCAL __BOLD + LOCAL __BOLD_LOOP + LOCAL __ITALIC + LOCAL __PRINT_EOL1 + LOCAL __PRINT_EOL2 + LOCAL __PRINT_AT1 + LOCAL __PRINT_AT2 + LOCAL __PRINT_AT2_END + LOCAL __PRINT_BOLD + LOCAL __PRINT_BOLD2 + LOCAL __PRINT_ITA + LOCAL __PRINT_ITA2 + LOCAL __PRINT_INK + LOCAL __PRINT_PAP + LOCAL __PRINT_SET_STATE + LOCAL __PRINT_TABLE + LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 + +__PRINT_TABLE: ; Jump table for 0 .. 22 codes + + DW __PRINT_NOP ; 0 + DW __PRINT_NOP ; 1 + DW __PRINT_NOP ; 2 + DW __PRINT_NOP ; 3 + DW __PRINT_NOP ; 4 + DW __PRINT_NOP ; 5 + DW __PRINT_COM ; 6 COMMA + DW __PRINT_NOP ; 7 + DW __PRINT_DEL ; 8 DEL + DW __PRINT_NOP ; 9 + DW __PRINT_NOP ; 10 + DW __PRINT_NOP ; 11 + DW __PRINT_NOP ; 12 + DW __PRINT_0Dh ; 13 + DW __PRINT_BOLD ; 14 + DW __PRINT_ITA ; 15 + DW __PRINT_INK ; 16 + DW __PRINT_PAP ; 17 + DW __PRINT_FLA ; 18 + DW __PRINT_BRI ; 19 + DW __PRINT_INV ; 20 + DW __PRINT_OVR ; 21 + DW __PRINT_AT ; 22 AT + DW __PRINT_TAB ; 23 TAB + + ENDP + + +#line 116 "read5.bas" +#line 1 "printf.asm" + +#line 1 "printstr.asm" + + + + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 5 "printstr.asm" + + ; PRINT command routine + ; Prints string pointed by HL + +PRINT_STR: +__PRINTSTR: ; __FASTCALL__ Entry to print_string + PROC + LOCAL __PRINT_STR_LOOP + LOCAL __PRINT_STR_END + + ld d, a ; Saves A reg (Flag) for later + + ld a, h + or l + ret z ; Return if the pointer is NULL + + push hl + + ld c, (hl) + inc hl + ld b, (hl) + inc hl ; BC = LEN(a$); HL = &a$ + +__PRINT_STR_LOOP: + ld a, b + or c + jr z, __PRINT_STR_END ; END if BC (counter = 0) + + ld a, (hl) + call __PRINTCHAR + inc hl + dec bc + jp __PRINT_STR_LOOP + +__PRINT_STR_END: + pop hl + ld a, d ; Recovers A flag + or a ; If not 0 this is a temporary string. Free it + ret z + jp __MEM_FREE ; Frees str from heap and return from there + +__PRINT_STR: + ; Fastcall Entry + ; It ONLY prints strings + ; HL = String start + ; BC = String length (Number of chars) + push hl ; Push str address for later + ld d, a ; Saves a FLAG + jp __PRINT_STR_LOOP + + ENDP + +#line 2 "printf.asm" + + + +__PRINTF: ; Prints a Fixed point Number stored in C ED LH + PROC + + LOCAL RECLAIM2 + LOCAL STK_END + STK_END EQU 5C65h + + ld hl, (ATTR_T) + push hl ; Saves ATTR_T since BUG ROM changes it + + ld hl, (STK_END) + push hl ; Stores STK_END + + call __FPSTACK_PUSH ; Push number into stack + rst 28h ; # Rom Calculator + defb 2Eh ; # STR$(x) + defb 38h ; # END CALC + call __FPSTACK_POP ; Recovers string parameters to A ED CB + + pop hl + ld (STK_END), hl ; Balance STK_END to avoid STR$ bug + + pop hl + ld (ATTR_T), hl ; Restores ATTR_T + + ex de, hl ; String position now in HL + + push bc + xor a ; Avoid the str to be FREED from heap + call __PRINT_STR + pop bc + inc bc + + jp RECLAIM2 ; Frees TMP Memory + + RECLAIM2 EQU 19E8h + + ENDP + +#line 117 "read5.bas" +#line 1 "read_restore.asm" + + ;; This implements READ & RESTORE functions + ;; Reads a new element from the DATA Address code + ;; Updates the DATA_ADDR read ptr for the next read + + ;; Data codification is 1 byte for type followed by data bytes + ;; Byte type is encoded as follows + +;; 00: End of data +;; 01: String +;; 02: Byte +;; 03: Ubyte +;; 04: Integer +;; 05: UInteger +;; 06: Long +;; 07: ULong +;; 08: Fixed +;; 09: Float + + ;; bit7 is set for a parameter-less function + ;; In that case, the next two bytes are the ptr of the function to jump + + +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 24 "read_restore.asm" +#line 1 "iload32.asm" + + ; __FASTCALL__ routine which + ; loads a 32 bits integer into DE,HL + ; stored at position pointed by POINTER HL + ; DE,HL <-- (HL) + +__ILOAD32: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + ex de, hl + ret + +#line 25 "read_restore.asm" +#line 1 "iloadf.asm" + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- ((HL)) + +__ILOADF: + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- (HL) + +__LOADF: ; Loads a 40 bits FP number from address pointed by HL + ld a, (hl) + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld c, (hl) + inc hl + ld b, (hl) + ret + +#line 26 "read_restore.asm" +#line 1 "ftof16reg.asm" + +#line 1 "ftou32reg.asm" + +#line 1 "neg32.asm" + +__ABS32: + bit 7, d + ret z + +__NEG32: ; Negates DEHL (Two's complement) + ld a, l + cpl + ld l, a + + ld a, h + cpl + ld h, a + + ld a, e + cpl + ld e, a + + ld a, d + cpl + ld d, a + + inc l + ret nz + + inc h + ret nz + + inc de + ret + +#line 2 "ftou32reg.asm" + +__FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + ; Output: DEHL 32 bit number (signed) + PROC + + LOCAL __IS_FLOAT + + or a + jr nz, __IS_FLOAT + ; Here if it is a ZX ROM Integer + + ld h, c + ld l, d + ld a, e ; Takes sign: FF = -, 0 = + + ld de, 0 + inc a + jp z, __NEG32 ; Negates if negative + ret + +__IS_FLOAT: ; Jumps here if it is a true floating point number + ld h, e + push hl ; Stores it for later (Contains Sign in H) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + ;ld a, c ; Get exponent + sub 128 ; Exponent -= 128 + jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + +__FTOU32REG_LOOP: + exx ; Shift C'B' E'D' << 1, output bit stays in Carry + sla d + rl e + rl b + rl c + + exx ; Shift DEHL << 1, inserting the carry on the right + rl l + rl h + rl e + rl d + + djnz __FTOU32REG_LOOP + +__FTOU32REG_END: + pop af ; Take the sign bit + or a ; Sets SGN bit to 1 if negative + jp m, __NEG32 ; Negates DEHL + + ret + + ENDP + + +__FTOU8: ; Converts float in C ED LH to Unsigned byte in A + call __FTOU32REG + ld a, l + ret + +#line 2 "ftof16reg.asm" + +__FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + + ld l, a ; Saves exponent for later + or d + or e + or b + or c + ld h, e + ret z ; Return if ZERO + + push hl ; Stores it for later (Contains sign in H, exponent in L) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + pop bc + + ld a, c ; Get exponent + sub 112 ; Exponent -= 128 + 16 + + push bc ; Saves sign in b again + + jp z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jp c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + 16 (we need to shift 16 bit more) + jp __FTOU32REG_LOOP ; proceed as an u32 integer + +#line 27 "read_restore.asm" +#line 1 "f16tofreg.asm" + + +#line 1 "u32tofreg.asm" + + +__I8TOFREG: + ld l, a + rlca + sbc a, a ; A = SGN(A) + ld h, a + ld e, a + ld d, a + +__I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) + ; to a Floating Point Number returned in (A ED CB) + + ld a, d + or a ; Test sign + + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __U32TOFREG ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + +__U8TOFREG: + ; Converts an unsigned 8 bit (A) to Floating point + ld l, a + ld h, 0 + ld e, h + ld d, h + +__U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in A ED CB + + PROC + + LOCAL __U32TOFREG_END + + ld a, d + or e + or h + or l + ld b, d + ld c, e ; Returns 00 0000 0000 if ZERO + ret z + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 128 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + +__U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG + exx + ld a, d ; B'C'D'E' == 0 ? + or e + or b + or c + jp z, __U32TOFREG_END ; We are done + + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry + rr c + rr d + rr e + exx + + rr e ; Shift EDCB >> 1, inserting the carry on the left + rr d + rr c + rr b + + inc l ; Increment exponent + jp __U32TOFREG_LOOP + + +__U32TOFREG_END: + exx + ld a, l ; Puts the exponent in a + res 7, e ; Sets the sign bit to 0 (positive) + + ret + ENDP + +#line 3 "f16tofreg.asm" + +__F16TOFREG: ; Converts a 16.16 signed fixed point (stored in DEHL) + ; to a Floating Point Number returned in (C ED CB) + PROC + + LOCAL __F16TOFREG2 + + ld a, d + or a ; Test sign + + jp p, __F16TOFREG2 ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __F16TOFREG2 ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + + +__F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in C DE HL + + ld a, d + or e + or h + or l + ld b, h + ld c, l + ret z ; Return 00 0000 0000 if 0 + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 112 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + jp __U32TOFREG_LOOP ; Proceed as an integer + + ENDP + +#line 28 "read_restore.asm" + + + + + + + + + + + + + + ;; Updates restore point to the given HL mem. address +__RESTORE: + PROC + LOCAL __DATA_ADDR + + ld (__DATA_ADDR), hl + ret + + ;; Reads a value from the DATA mem area and updates __DATA_ADDR ptr to the + ;; next item. On Out Of Data, restarts + ;; +__READ: + LOCAL read_restart, cont, cont2, table, no_func + LOCAL dynamic_cast, dynamic_cast2, dynamic_cast3, dynamic_cast4 + LOCAL _decode_table, coerce_to_int, coerce_to_int2, promote_to_i16 + LOCAL _from_i8, _from_u8 + LOCAL _from_i16, _from_u16 + LOCAL _from_i32, _from_u32 + LOCAL _from_fixed, __data_error + + push af ; type of data to read + ld hl, (__DATA_ADDR) +read_restart: + ld a, (hl) + or a ; 0 => OUT of data + jr nz, cont + ;; Signals out of data + + ld hl, __DATA__0 + ld (__DATA_ADDR), hl + jr read_restart ; Start again +cont: + and 0x80 + ld a, (hl) + push af + jp z, no_func ;; Loads data directly, not a function + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl +cont2: + ld de, dynamic_cast + push de ; ret address + jp (hl) ; "call (hl)" + + ;; Now tries to convert the given result to the expected type or raise an error +dynamic_cast: + exx + ex af, af' + pop af ; type READ + and 0x7F ; clear bit 7 + pop hl ; type requested by USER (type of the READ variable) + ld c, h ; save requested type (save it in register C) + cp h + exx + jr nz, dynamic_cast2 ; Types are identical? + ;; yes, they are + ex af, af' + ret + +dynamic_cast2: + cp 1 ; Requested a number, but read a string? + jr nz, dynamic_cast3 + call __MEM_FREE ; Frees str from memory + jr __data_error + +dynamic_cast3: + exx + ld b, a ; Read type + ld a, c ; Requested type + cp 1 + jr z, __data_error + cp b + jr c, dynamic_cast4 + ;; here the user expected type is "larger" than the read one + ld a, b + sub 2 + add a, a + ld l, a + ld h, 0 + ld de, _decode_table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl + ld a, c ; Requested type + exx + ret + +__data_error: + ;; When a data is read, but cannot be converted to the requested type + ;; that is, the user asked for a string and we read a number or vice versa + ld a, ERROR_InvalidArg + call __STOP ; The user expected a string, but read a number + xor a + ld h, a + ld l, a + ld e, a + ld d, a + ld b, a + ld c, a + ret + +_decode_table: + dw _from_i8 + dw _from_u8 + dw _from_i16 + dw _from_u16 + dw _from_i32 + dw _from_u32 + dw _from_fixed + +_from_i8: + cp 4 + jr nc, promote_to_i16 + ex af, af' + ret ;; Was from Byte to Ubyte + +promote_to_i16: + ex af, af' + ld l, a + rla + sbc a, a + ld h, a ; copy sgn to h + ex af, af' + jr _before_from_i16 + +_from_u8: + ex af, af' + ld l, a + ld h, 0 + ex af, af' + ;; Promoted to i16 + +_before_from_i16: +_from_i16: + cp 6 + ret c ;; from i16 to u16 + ;; Promote i16 to i32 + ex af, af' + ld a, h + rla + sbc a, a + ld e, a + ld d, a + ex af, af' +_from_i32: + cp 7 + ret z ;; From i32 to u32 + ret c ;; From u16 to i32 + cp 9 + jp z, __I32TOFREG +_from_u32: + cp 9 + jp z, __U32TOFREG + ex de, hl + ld hl, 0 + cp 8 + ret z +_from_fixed: ;; From fixed to float + jp __F16TOFREG +_from_u16: + ld de, 0 ; HL 0x0000 => 32 bits + jp _from_i32 + +dynamic_cast4: + ;; The user type is "shorter" than the read one + cp 8 ;; required type + jr c, before_to_int ;; required < fixed (f16) + ex af, af' + exx ;; Ok, we must convert from float to f16 + jp __FTOF16REG + +before_to_int: + ld a, b ;; read type + cp 8 ;; + jr nz, coerce_to_int ;; From float to int + ld a, c ;; user type + exx + ;; f16 to Long + ex de, hl + ld a, h + rla + sbc a, a + ld d, a + ld e, a + exx + jr coerce_to_int2 +coerce_to_int: + exx + ex af, af' + call __FTOU32REG + ex af, af' ; a contains user type + exx +coerce_to_int2: ; At this point we have an u/integer in hl + exx + cp 4 + ret nc ; Already done. Return the result + ld a, l ; Truncate to byte + ret + +no_func: + exx + ld de, dynamic_cast + push de ; Ret address + dec a ; 0 => string; 1, 2 => byte; 3, 4 => integer; 5, 6 => long, 7 => fixed; 8 => float + ld h, 0 + add a, a + ld l, a + ld de, table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl ; address to jump to + exx + inc hl + ret ; jp (sp) => jump to table[a - 1] + +table: + LOCAL __01_decode_string + LOCAL __02_decode_byte + LOCAL __03_decode_ubyte + LOCAL __04_decode_integer + LOCAL __05_decode_uinteger + LOCAL __06_decode_long + LOCAL __07_decode_ulong + LOCAL __08_decode_fixed + LOCAL __09_decode_float + + ;; 1 -> Decode string + ;; 2, 3 -> Decode Byte, UByte + ;; 4, 5 -> Decode Integer, UInteger + ;; 6, 7 -> Decode Long, ULong + ;; 8 -> Decode Fixed + ;; 9 -> Decode Float + dw __01_decode_string + dw __02_decode_byte + dw __03_decode_ubyte + dw __04_decode_integer + dw __05_decode_uinteger + dw __06_decode_long + dw __07_decode_ulong + dw __08_decode_fixed + dw __09_decode_float + +__01_decode_string: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl + jp __LOADSTR + +__02_decode_byte: +__03_decode_ubyte: + ld a, (hl) + inc hl + ld (__DATA_ADDR), hl + ret + +__04_decode_integer: +__05_decode_uinteger: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl + ex de, hl + ret + +__06_decode_long: +__07_decode_ulong: +__08_decode_fixed: + ld b, h + ld c, l + inc bc + inc bc + inc bc + inc bc + ld (__DATA_ADDR), bc + jp __ILOAD32 + +__09_decode_float: + call __LOADF + inc hl + ld (__DATA_ADDR), hl + ld h, a ; returns A in H; sets A free + ret + +__DATA_ADDR: ;; Stores current DATA ptr + dw __DATA__0 + ENDP + + + + + + + + + + +#line 118 "read5.bas" +#line 1 "sin.asm" + + + +SIN: ; Computes SIN using ROM FP-CALC + call __FPSTACK_PUSH + + rst 28h ; ROM CALC + defb 1Fh + defb 38h ; END CALC + + jp __FPSTACK_POP + +#line 119 "read5.bas" +#line 1 "storef.asm" + +__PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) + push de + ex de, hl ; DE <- HL + push ix + pop hl ; HL <- IX + add hl, de ; HL <- IX + HL + pop de + +__ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register + ex af, af' + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex af, af' + +__STOREF: ; Stores the given FP number in A EDCB at address HL + ld (hl), a + inc hl + ld (hl), e + inc hl + ld (hl), d + inc hl + ld (hl), c + inc hl + ld (hl), b + ret + +#line 120 "read5.bas" +#line 1 "tan.asm" + + + +TAN: ; Computes TAN using ROM FP-CALC + call __FPSTACK_PUSH + + rst 28h ; ROM CALC + defb 21h ; TAN + defb 38h ; END CALC + + jp __FPSTACK_POP + +#line 121 "read5.bas" + +ZXBASIC_USER_DATA: +_v: + DEFB 81h + DEFB 40h + DEFB 00h + DEFB 00h + DEFB 00h +_c: + DEFB 00, 00, 00, 00, 00 +_d: + DEFB 00, 00, 00, 00, 00 +_i: + DEFB 00 +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/read5.bas b/tests/functional/read5.bas new file mode 100644 index 000000000..c6e92284b --- /dev/null +++ b/tests/functional/read5.bas @@ -0,0 +1,18 @@ +REM Error x is an array, not an scalar + +DIM v as Float = 1.5 + +RESTORE + +DATA 10, 25 * v, SIN(v) * tan(v)^2, PI * v + + +DIM c, d as Float +FOR i = 1 TO 4: +READ c, d +PRINT c, d +NEXT i + + + + diff --git a/tests/functional/read6.bas b/tests/functional/read6.bas new file mode 100644 index 000000000..5d260da7a --- /dev/null +++ b/tests/functional/read6.bas @@ -0,0 +1,18 @@ +REM Error x is an array, not an scalar + +DIM v as Float = 1.5 + +RESTORE + +DATA 10, 25 * v, SIN(v) * tan(v)^2, PI * v + + +DIM c, d as Float +FOR i = 1 TO 4: +READ c * d +PRINT c +NEXT i + + + + diff --git a/tests/functional/read7.bas b/tests/functional/read7.bas new file mode 100644 index 000000000..7dcfc1819 --- /dev/null +++ b/tests/functional/read7.bas @@ -0,0 +1,17 @@ +REM Error x is an array, not an scalar + +DIM v as Float = 1.5 + +RESTORE + +DATA 10, 25 * v, SIN(v) * tan(v)^2, PI * v + + +DIM c(5) as Float +FOR i = 1 TO 4: +READ c +NEXT i + + + + diff --git a/tests/functional/read8.asm b/tests/functional/read8.asm new file mode 100644 index 000000000..0708f8db6 --- /dev/null +++ b/tests/functional/read8.asm @@ -0,0 +1,2794 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + call __PRINT_INIT + ld hl, __DATA__0 + call __RESTORE + ld a, 1 + ld (_i), a + jp __LABEL0 +__LABEL3: + ld a, 9 + call __READ + ld hl, _c + 8 + call __STOREF + ld a, (_c + 8) + ld de, (_c + 8 + 1) + ld bc, (_c + 8 + 3) + call __PRINTF + call PRINT_EOL +__LABEL4: + ld a, (_i) + inc a + ld (_i), a +__LABEL0: + ld a, 4 + ld hl, (_i - 1) + cp h + jp nc, __LABEL3 +__LABEL2: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +___DATA__FUNCPTR__0: + ld a, (_v) + ld de, (_v + 1) + ld bc, (_v + 3) + ld hl, 00000h + push hl + ld hl, 00048h + push hl + ld h, 085h + push hl + call __MULF + jp ___DATA__FUNCPTR__0__leave +___DATA__FUNCPTR__0__leave: + ret +___DATA__FUNCPTR__1: + ld a, (_v) + ld de, (_v + 1) + ld bc, (_v + 3) + call SIN + push bc + push de + push af + ld a, (_v) + ld de, (_v + 1) + ld bc, (_v + 3) + call TAN + push bc + push de + push af + ld a, 082h + ld de, 00000h + ld bc, 00000h + call __POW + call __MULF + jp ___DATA__FUNCPTR__1__leave +___DATA__FUNCPTR__1__leave: + ret +___DATA__FUNCPTR__2: + ld a, (_v) + ld de, (_v + 1) + ld bc, (_v + 3) + ld hl, 0A2DAh + push hl + ld hl, 00F49h + push hl + ld h, 082h + push hl + call __MULF + jp ___DATA__FUNCPTR__2__leave +___DATA__FUNCPTR__2__leave: + ret +__DATA__0: + DEFB 3 + DEFB 10 + DEFB 89h + DEFW ___DATA__FUNCPTR__0 + DEFB 89h + DEFW ___DATA__FUNCPTR__1 + DEFB 89h + DEFW ___DATA__FUNCPTR__2 +__DATA__END: + DEFB 00h +#line 1 "mulf.asm" + +#line 1 "stackf.asm" + + ; ------------------------------------------------------------- + ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC + ; ------------------------------------------------------------- + + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) + __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) + +__FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) + ; Second argument to push into the stack calculator is popped out of the stack + ; Since the caller routine also receives the parameters into the top of the stack + ; four bytes must be removed from SP before pop them out + + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK + exx + pop hl ; Caller-Caller return addr + exx + pop hl ; Caller return addr + + pop af + pop de + pop bc + + push hl ; Caller return addr + exx + push hl ; Caller-Caller return addr + exx + + jp __FPSTACK_PUSH + + +__FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK + ; This format is specified in the ZX 48K Manual + ; You can push a 16 bit signed integer as + ; 0 SS LL HH 0, being SS the sign and LL HH the low + ; and High byte respectively + ld a, h + rla ; sign to Carry + sbc a, a ; 0 if positive, FF if negative + ld e, a + ld d, l + ld c, h + xor a + ld b, a + jp __FPSTACK_PUSH +#line 2 "mulf.asm" + + ; ------------------------------------------------------------- + ; Floating point library using the FP ROM Calculator (ZX 48K) + ; All of them uses A EDCB registers as 1st paramter. + ; For binary operators, the 2n operator must be pushed into the + ; stack, in the order A DE BC. + ; + ; Uses CALLEE convention + ; ------------------------------------------------------------- + +__MULF: ; Multiplication + call __FPSTACK_PUSH2 + + ; ------------- ROM MUL + rst 28h + defb 04h ; + defb 38h; ; END CALC + + jp __FPSTACK_POP + +#line 105 "read8.bas" +#line 1 "pow.asm" + + + + ; ------------------------------------------------------------- + ; Floating point library using the FP ROM Calculator (ZX 48K) + + ; All of them uses A EDCB registers as 1st paramter. + ; For binary operators, the 2n operator must be pushed into the + ; stack, in the order A DE BC. + ; + ; Uses CALLEE convention + ; +; Operands comes swapped: + ; 1 st parameter is the BASE (A ED CB) + ; 2 nd parameter (Top of the stack) is Exponent + ; ------------------------------------------------------------- + +__POW: ; Exponentiation + PROC + + call __FPSTACK_PUSH2 + + ; ------------- ROM POW + rst 28h + defb 01h ; Exchange => 1, Base + defb 06h ; POW + defb 38h; ; END CALC + + jp __FPSTACK_POP + + ENDP + +#line 106 "read8.bas" +#line 1 "print.asm" + +; vim:ts=4:sw=4:et: + ; PRINT command routine + ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that + +#line 1 "sposn.asm" + + ; Printing positioning library. + PROC + LOCAL ECHO_E + +__LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. + ld de, (S_POSN) + ld hl, (MAXX) + or a + sbc hl, de + ex de, hl + ret + + +__SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. + ld hl, (MAXX) + or a + sbc hl, de + ld (S_POSN), hl ; saves it again + ret + + + ECHO_E EQU 23682 + MAXX EQU ECHO_E ; Max X position + 1 + MAXY EQU MAXX + 1 ; Max Y position + 1 + + S_POSN EQU 23688 + POSX EQU S_POSN ; Current POS X + POSY EQU S_POSN + 1 ; Current POS Y + + ENDP + +#line 6 "print.asm" +#line 1 "cls.asm" + + ; JUMPS directly to spectrum CLS + ; This routine does not clear lower screen + + ;CLS EQU 0DAFh + + ; Our faster implementation + + + +CLS: + PROC + + LOCAL COORDS + LOCAL __CLS_SCR + LOCAL ATTR_P + LOCAL SCREEN + + ld hl, 0 + ld (COORDS), hl + ld hl, 1821h + ld (S_POSN), hl +__CLS_SCR: + ld hl, SCREEN + ld (hl), 0 + ld d, h + ld e, l + inc de + ld bc, 6144 + ldir + + ; Now clear attributes + + ld a, (ATTR_P) + ld (hl), a + ld bc, 767 + ldir + ret + + COORDS EQU 23677 + SCREEN EQU 16384 ; Default start of the screen (can be changed) + ATTR_P EQU 23693 + ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address + + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines + ; to get the start of the screen + ENDP + +#line 7 "print.asm" +#line 1 "in_screen.asm" + + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 3 "in_screen.asm" + +__IN_SCREEN: + ; Returns NO carry if current coords (D, E) + ; are OUT of the screen limits (MAXX, MAXY) + + PROC + LOCAL __IN_SCREEN_ERR + + ld hl, MAXX + ld a, e + cp (hl) + jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + + ld a, d + inc hl + cp (hl) + ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + ;; ret + ret c ; Return if carry (OK) + +__IN_SCREEN_ERR: +__OUT_OF_SCREEN_ERR: + ; Jumps here if out of screen + ld a, ERROR_OutOfScreen + jp __STOP ; Saves error code and exits + + ENDP +#line 8 "print.asm" +#line 1 "table_jump.asm" + + +JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A + add a, a + +JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE + ld e, a + ld d, 0 + +JUMP_HL_PLUS_DE: ; Does JP (HL + DE) + add hl, de + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl +CALL_HL: + jp (hl) + +#line 9 "print.asm" +#line 1 "ink.asm" + + ; Sets ink color in ATTR_P permanently +; Parameter: Paper color in A register + +#line 1 "const.asm" + + ; Global constants + + P_FLAG EQU 23697 + FLAGS2 EQU 23681 + ATTR_P EQU 23693 ; permanet ATTRIBUTES + ATTR_T EQU 23695 ; temporary ATTRIBUTES + CHARS EQU 23606 ; Pointer to ROM/RAM Charset + UDG EQU 23675 ; Pointer to UDG Charset + MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars + +#line 5 "ink.asm" + +INK: + PROC + LOCAL __SET_INK + LOCAL __SET_INK2 + + ld de, ATTR_P + +__SET_INK: + cp 8 + jr nz, __SET_INK2 + + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + or 7 ; Set bits 0,1,2 to enable transparency + ld (de), a + ret + +__SET_INK2: + ; Another entry. This will set the ink color at location pointer by DE + and 7 ; # Gets color mod 8 + ld b, a ; Saves the color + ld a, (de) + and 0F8h ; Clears previous value + or b + ld (de), a + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + and 0F8h ; Reset bits 0,1,2 sign to disable transparency + ld (de), a ; Store new attr + ret + + ; Sets the INK color passed in A register in the ATTR_T variable +INK_TMP: + ld de, ATTR_T + jp __SET_INK + + ENDP + +#line 10 "print.asm" +#line 1 "paper.asm" + + ; Sets paper color in ATTR_P permanently +; Parameter: Paper color in A register + + + +PAPER: + PROC + LOCAL __SET_PAPER + LOCAL __SET_PAPER2 + + ld de, ATTR_P + +__SET_PAPER: + cp 8 + jr nz, __SET_PAPER2 + inc de + ld a, (de) + or 038h + ld (de), a + ret + + ; Another entry. This will set the paper color at location pointer by DE +__SET_PAPER2: + and 7 ; # Remove + rlca + rlca + rlca ; a *= 8 + + ld b, a ; Saves the color + ld a, (de) + and 0C7h ; Clears previous value + or b + ld (de), a + inc de ; Points to MASK_T or MASK_P accordingly + ld a, (de) + and 0C7h ; Resets bits 3,4,5 + ld (de), a + ret + + + ; Sets the PAPER color passed in A register in the ATTR_T variable +PAPER_TMP: + ld de, ATTR_T + jp __SET_PAPER + ENDP + +#line 11 "print.asm" +#line 1 "flash.asm" + + ; Sets flash flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +FLASH: + ld de, ATTR_P +__SET_FLASH: + ; Another entry. This will set the flash flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + ld b, a ; Saves the color + ld a, (de) + and 07Fh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the FLASH flag passed in A register in the ATTR_T variable +FLASH_TMP: + ld de, ATTR_T + jr __SET_FLASH + +#line 12 "print.asm" +#line 1 "bright.asm" + + ; Sets bright flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +BRIGHT: + ld de, ATTR_P + +__SET_BRIGHT: + ; Another entry. This will set the bright flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + rrca + ld b, a ; Saves the color + ld a, (de) + and 0BFh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable +BRIGHT_TMP: + ld de, ATTR_T + jr __SET_BRIGHT + +#line 13 "print.asm" +#line 1 "over.asm" + + ; Sets OVER flag in P_FLAG permanently +; Parameter: OVER flag in bit 0 of A register +#line 1 "copy_attr.asm" + + + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" + + + +COPY_ATTR: + ; Just copies current permanent attribs to temporal attribs + ; and sets print mode + PROC + + LOCAL INVERSE1 + LOCAL __REFRESH_TMP + + INVERSE1 EQU 02Fh + + ld hl, (ATTR_P) + ld (ATTR_T), hl + + ld hl, FLAGS2 + call __REFRESH_TMP + + ld hl, P_FLAG + call __REFRESH_TMP + + +__SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) + + + LOCAL TABLE + LOCAL CONT2 + + rra ; Over bit to carry + ld a, (FLAGS2) + rla ; Over bit in bit 1, Over2 bit in bit 2 + and 3 ; Only bit 0 and 1 (OVER flag) + + ld c, a + ld b, 0 + + ld hl, TABLE + add hl, bc + ld a, (hl) + ld (PRINT_MODE), a + + ld hl, (P_FLAG) + xor a ; NOP -> INVERSE0 + bit 2, l + jr z, CONT2 + ld a, INVERSE1 ; CPL -> INVERSE1 + +CONT2: + ld (INVERSE_MODE), a + ret + +TABLE: + nop ; NORMAL MODE + xor (hl) ; OVER 1 MODE + and (hl) ; OVER 2 MODE + or (hl) ; OVER 3 MODE + +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" + +__REFRESH_TMP: + ld a, (hl) + and 10101010b + ld c, a + rra + or c + ld (hl), a + ret + + ENDP + +#line 4 "over.asm" + + +OVER: + PROC + + ld c, a ; saves it for later + and 2 + ld hl, FLAGS2 + res 1, (HL) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 ; # Convert to 0/1 + add a, a; # Shift left 1 bit for permanent + + ld hl, P_FLAG + res 1, (hl) + or (hl) + ld (hl), a + ret + + ; Sets OVER flag in P_FLAG temporarily +OVER_TMP: + ld c, a ; saves it for later + and 2 ; gets bit 1; clears carry + rra + ld hl, FLAGS2 + res 0, (hl) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 + ld hl, P_FLAG + res 0, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 14 "print.asm" +#line 1 "inverse.asm" + + ; Sets INVERSE flag in P_FLAG permanently +; Parameter: INVERSE flag in bit 0 of A register + + + +INVERSE: + PROC + + and 1 ; # Convert to 0/1 + add a, a; # Shift left 3 bits for permanent + add a, a + add a, a + ld hl, P_FLAG + res 3, (hl) + or (hl) + ld (hl), a + ret + + ; Sets INVERSE flag in P_FLAG temporarily +INVERSE_TMP: + and 1 + add a, a + add a, a; # Shift left 2 bits for temporary + ld hl, P_FLAG + res 2, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 15 "print.asm" +#line 1 "bold.asm" + + ; Sets BOLD flag in P_FLAG permanently +; Parameter: BOLD flag in bit 0 of A register + + +BOLD: + PROC + + and 1 + rlca + rlca + rlca + ld hl, FLAGS2 + res 3, (HL) + or (hl) + ld (hl), a + ret + + ; Sets BOLD flag in P_FLAG temporarily +BOLD_TMP: + and 1 + rlca + rlca + ld hl, FLAGS2 + res 2, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 16 "print.asm" +#line 1 "italic.asm" + + ; Sets ITALIC flag in P_FLAG permanently +; Parameter: ITALIC flag in bit 0 of A register + + +ITALIC: + PROC + + and 1 + rrca + rrca + rrca + ld hl, FLAGS2 + res 5, (HL) + or (hl) + ld (hl), a + ret + + ; Sets ITALIC flag in P_FLAG temporarily +ITALIC_TMP: + and 1 + rrca + rrca + rrca + rrca + ld hl, FLAGS2 + res 4, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 17 "print.asm" + +#line 1 "attr.asm" + + ; Attribute routines +; vim:ts=4:et:sw: + + + + + + + +__ATTR_ADDR: + ; calc start address in DE (as (32 * d) + e) + ; Contributed by Santiago Romero at http://www.speccy.org + ld h, 0 ; 7 T-States + ld a, d ; 4 T-States + add a, a ; a * 2 ; 4 T-States + add a, a ; a * 4 ; 4 T-States + ld l, a ; HL = A * 4 ; 4 T-States + + add hl, hl ; HL = A * 8 ; 15 T-States + add hl, hl ; HL = A * 16 ; 15 T-States + add hl, hl ; HL = A * 32 ; 15 T-States + + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) + add hl, de + + ld de, (SCREEN_ADDR) ; Adds the screen address + add hl, de + + ; Return current screen address in HL + ret + + + ; Sets the attribute at a given screen coordinate (D, E). + ; The attribute is taken from the ATTR_T memory variable + ; Used by PRINT routines +SET_ATTR: + + ; Checks for valid coords + call __IN_SCREEN + ret nc + +__SET_ATTR: + ; Internal __FASTCALL__ Entry used by printing routines + PROC + + call __ATTR_ADDR + ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T + + ld a, d + and (hl) + ld c, a ; C = current screen color, masked + + ld a, d + cpl ; Negate mask + and e ; Mask current attributes + or c ; Mix them + ld (hl), a ; Store result in screen + + ret + + ENDP + + +#line 19 "print.asm" + + ; Putting a comment starting with @INIT
+ ; will make the compiler to add a CALL to
+ ; It is useful for initialization routines. + + +__PRINT_INIT: ; To be called before program starts (initializes library) + PROC + + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + + ld hl, 1821h + ld (MAXX), hl ; Sets current maxX and maxY + + xor a + ld (FLAGS2), a + + ret + + +__PRINTCHAR: ; Print character store in accumulator (A register) + ; Modifies H'L', B'C', A'F', D'E', A + + LOCAL PO_GR_1 + + LOCAL __PRCHAR + LOCAL __PRINT_CONT + LOCAL __PRINT_CONT2 + LOCAL __PRINT_JUMP + LOCAL __SRCADDR + LOCAL __PRINT_UDG + LOCAL __PRGRAPH + LOCAL __PRINT_START + + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 + +__PRINT_JUMP: + jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively + +__PRINT_START: + cp ' ' + jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones + + exx ; Switch to alternative registers + ex af, af' ; Saves a value (char to print) for later + + call __LOAD_S_POSN + + ; At this point we have the new coord + ld hl, (SCREEN_ADDR) + + ld a, d + ld c, a ; Saves it for later + + and 0F8h ; Masks 3 lower bit ; zy + ld d, a + + ld a, c ; Recovers it + and 07h ; MOD 7 ; y1 + rrca + rrca + rrca + + or e + ld e, a + add hl, de ; HL = Screen address + DE + ex de, hl ; DE = Screen address + + ex af, af' + + cp 80h ; Is it an UDG or a ? + jp c, __SRCADDR + + cp 90h + jp nc, __PRINT_UDG + + ; Print a 8 bit pattern (80h to 8Fh) + + ld b, a + call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 + ld hl, MEM0 + jp __PRGRAPH + + PO_GR_1 EQU 0B38h + +__PRINT_UDG: + sub 90h ; Sub ASC code + ld bc, (UDG) + jp __PRGRAPH0 + + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source +__SRCADDR: + ld bc, (CHARS) + +__PRGRAPH0: + add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org + ld l, a + ld h, 0 ; HL = a * 2 (accumulator) + add hl, hl + add hl, hl ; HL = a * 8 + add hl, bc ; HL = CHARS address + +__PRGRAPH: + ex de, hl ; HL = Write Address, DE = CHARS address + bit 2, (iy + $47) + call nz, __BOLD + bit 4, (iy + $47) + call nz, __ITALIC + ld b, 8 ; 8 bytes per char +__PRCHAR: + ld a, (de) ; DE *must* be ALWAYS source, and HL destiny + +PRINT_MODE: ; Which operation is used to write on the screen + ; Set it with: + ; LD A, + ; LD (PRINT_MODE), A + ; + ; Available opertions: + ; NORMAL: 0h --> NOP ; OVER 0 + ; XOR : AEh --> XOR (HL) ; OVER 1 + ; OR : B6h --> OR (HL) ; PUTSPRITE + ; AND : A6h --> AND (HL) ; PUTMASK + nop ; + +INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 + nop ; 2F -> CPL -> INVERSE 1 + + ld (hl), a + + inc de + inc h ; Next line + djnz __PRCHAR + + call __LOAD_S_POSN + push de + call __SET_ATTR + pop de + inc e ; COL = COL + 1 + ld hl, (MAXX) + ld a, e + dec l ; l = MAXX + cp l ; Lower than max? + jp c, __PRINT_CONT; Nothing to do + call __PRINT_EOL1 + exx ; counteracts __PRINT_EOL1 exx + jp __PRINT_CONT2 + +__PRINT_CONT: + call __SAVE_S_POSN + +__PRINT_CONT2: + exx + ret + + ; ------------- SPECIAL CHARS (< 32) ----------------- + +__PRINT_SPECIAL: ; Jumps here if it is a special char + exx + ld hl, __PRINT_TABLE + jp JUMP_HL_PLUS_2A + + +PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence + exx + +__PRINT_0Dh: ; Called WHEN printing CHR$(13) + call __LOAD_S_POSN + +__PRINT_EOL1: ; Another entry called from PRINT when next line required + ld e, 0 + +__PRINT_EOL2: + ld a, d + inc a + +__PRINT_AT1_END: + ld hl, (MAXY) + cp l + jr c, __PRINT_EOL_END ; Carry if (MAXY) < d + xor a + +__PRINT_EOL_END: + ld d, a + +__PRINT_AT2_END: + call __SAVE_S_POSN + exx + ret + +__PRINT_COM: + exx + push hl + push de + push bc + call PRINT_COMMA + pop bc + pop de + pop hl + ret + +__PRINT_TAB: + ld hl, __PRINT_TAB1 + jp __PRINT_SET_STATE + +__PRINT_TAB1: + ld (MEM0), a + ld hl, __PRINT_TAB2 + ld (PRINT_JUMP_STATE), hl + ret + +__PRINT_TAB2: + ld a, (MEM0) ; Load tab code (ignore the current one) + push hl + push de + push bc + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + call PRINT_TAB + pop bc + pop de + pop hl + ret + +__PRINT_NOP: +__PRINT_RESTART: + ld hl, __PRINT_START + jp __PRINT_SET_STATE + +__PRINT_AT: + ld hl, __PRINT_AT1 + +__PRINT_SET_STATE: + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + exx + ret + +__PRINT_AT1: ; Jumps here if waiting for 1st parameter + exx + ld hl, __PRINT_AT2 + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + jp __PRINT_AT1_END + +__PRINT_AT2: + exx + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + ld e, a + ld hl, (MAXX) + cp (hl) + jr c, __PRINT_AT2_END + jr __PRINT_EOL1 + +__PRINT_DEL: + call __LOAD_S_POSN ; Gets current screen position + dec e + ld a, -1 + cp e + jp nz, __PRINT_AT2_END + ld hl, (MAXX) + ld e, l + dec e + dec e + dec d + cp d + jp nz, __PRINT_AT2_END + ld d, h + dec d + jp __PRINT_AT2_END + +__PRINT_INK: + ld hl, __PRINT_INK2 + jp __PRINT_SET_STATE + +__PRINT_INK2: + exx + call INK_TMP + jp __PRINT_RESTART + +__PRINT_PAP: + ld hl, __PRINT_PAP2 + jp __PRINT_SET_STATE + +__PRINT_PAP2: + exx + call PAPER_TMP + jp __PRINT_RESTART + +__PRINT_FLA: + ld hl, __PRINT_FLA2 + jp __PRINT_SET_STATE + +__PRINT_FLA2: + exx + call FLASH_TMP + jp __PRINT_RESTART + +__PRINT_BRI: + ld hl, __PRINT_BRI2 + jp __PRINT_SET_STATE + +__PRINT_BRI2: + exx + call BRIGHT_TMP + jp __PRINT_RESTART + +__PRINT_INV: + ld hl, __PRINT_INV2 + jp __PRINT_SET_STATE + +__PRINT_INV2: + exx + call INVERSE_TMP + jp __PRINT_RESTART + +__PRINT_OVR: + ld hl, __PRINT_OVR2 + jp __PRINT_SET_STATE + +__PRINT_OVR2: + exx + call OVER_TMP + jp __PRINT_RESTART + +__PRINT_BOLD: + ld hl, __PRINT_BOLD2 + jp __PRINT_SET_STATE + +__PRINT_BOLD2: + exx + call BOLD_TMP + jp __PRINT_RESTART + +__PRINT_ITA: + ld hl, __PRINT_ITA2 + jp __PRINT_SET_STATE + +__PRINT_ITA2: + exx + call ITALIC_TMP + jp __PRINT_RESTART + + +__BOLD: + push hl + ld hl, MEM0 + ld b, 8 +__BOLD_LOOP: + ld a, (de) + ld c, a + rlca + or c + ld (hl), a + inc hl + inc de + djnz __BOLD_LOOP + pop hl + ld de, MEM0 + ret + + +__ITALIC: + push hl + ld hl, MEM0 + ex de, hl + ld bc, 8 + ldir + ld hl, MEM0 + srl (hl) + inc hl + srl (hl) + inc hl + srl (hl) + inc hl + inc hl + inc hl + sla (hl) + inc hl + sla (hl) + inc hl + sla (hl) + pop hl + ld de, MEM0 + ret + +PRINT_COMMA: + call __LOAD_S_POSN + ld a, e + and 16 + add a, 16 + +PRINT_TAB: + PROC + LOCAL LOOP, CONTINUE + + inc a + call __LOAD_S_POSN ; e = current row + ld d, a + ld a, e + cp 21h + jr nz, CONTINUE + ld e, -1 +CONTINUE: + ld a, d + inc e + sub e ; A = A - E + and 31 ; + ret z ; Already at position E + ld b, a +LOOP: + ld a, ' ' + call __PRINTCHAR + djnz LOOP + ret + ENDP + +PRINT_AT: ; CHanges cursor to ROW, COL + ; COL in A register + ; ROW in stack + + pop hl ; Ret address + ex (sp), hl ; callee H = ROW + ld l, a + ex de, hl + + call __IN_SCREEN + ret nc ; Return if out of screen + + jp __SAVE_S_POSN + + LOCAL __PRINT_COM + LOCAL __BOLD + LOCAL __BOLD_LOOP + LOCAL __ITALIC + LOCAL __PRINT_EOL1 + LOCAL __PRINT_EOL2 + LOCAL __PRINT_AT1 + LOCAL __PRINT_AT2 + LOCAL __PRINT_AT2_END + LOCAL __PRINT_BOLD + LOCAL __PRINT_BOLD2 + LOCAL __PRINT_ITA + LOCAL __PRINT_ITA2 + LOCAL __PRINT_INK + LOCAL __PRINT_PAP + LOCAL __PRINT_SET_STATE + LOCAL __PRINT_TABLE + LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 + +__PRINT_TABLE: ; Jump table for 0 .. 22 codes + + DW __PRINT_NOP ; 0 + DW __PRINT_NOP ; 1 + DW __PRINT_NOP ; 2 + DW __PRINT_NOP ; 3 + DW __PRINT_NOP ; 4 + DW __PRINT_NOP ; 5 + DW __PRINT_COM ; 6 COMMA + DW __PRINT_NOP ; 7 + DW __PRINT_DEL ; 8 DEL + DW __PRINT_NOP ; 9 + DW __PRINT_NOP ; 10 + DW __PRINT_NOP ; 11 + DW __PRINT_NOP ; 12 + DW __PRINT_0Dh ; 13 + DW __PRINT_BOLD ; 14 + DW __PRINT_ITA ; 15 + DW __PRINT_INK ; 16 + DW __PRINT_PAP ; 17 + DW __PRINT_FLA ; 18 + DW __PRINT_BRI ; 19 + DW __PRINT_INV ; 20 + DW __PRINT_OVR ; 21 + DW __PRINT_AT ; 22 AT + DW __PRINT_TAB ; 23 TAB + + ENDP + + +#line 107 "read8.bas" +#line 1 "printf.asm" + +#line 1 "printstr.asm" + + + + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 5 "printstr.asm" + + ; PRINT command routine + ; Prints string pointed by HL + +PRINT_STR: +__PRINTSTR: ; __FASTCALL__ Entry to print_string + PROC + LOCAL __PRINT_STR_LOOP + LOCAL __PRINT_STR_END + + ld d, a ; Saves A reg (Flag) for later + + ld a, h + or l + ret z ; Return if the pointer is NULL + + push hl + + ld c, (hl) + inc hl + ld b, (hl) + inc hl ; BC = LEN(a$); HL = &a$ + +__PRINT_STR_LOOP: + ld a, b + or c + jr z, __PRINT_STR_END ; END if BC (counter = 0) + + ld a, (hl) + call __PRINTCHAR + inc hl + dec bc + jp __PRINT_STR_LOOP + +__PRINT_STR_END: + pop hl + ld a, d ; Recovers A flag + or a ; If not 0 this is a temporary string. Free it + ret z + jp __MEM_FREE ; Frees str from heap and return from there + +__PRINT_STR: + ; Fastcall Entry + ; It ONLY prints strings + ; HL = String start + ; BC = String length (Number of chars) + push hl ; Push str address for later + ld d, a ; Saves a FLAG + jp __PRINT_STR_LOOP + + ENDP + +#line 2 "printf.asm" + + + +__PRINTF: ; Prints a Fixed point Number stored in C ED LH + PROC + + LOCAL RECLAIM2 + LOCAL STK_END + STK_END EQU 5C65h + + ld hl, (ATTR_T) + push hl ; Saves ATTR_T since BUG ROM changes it + + ld hl, (STK_END) + push hl ; Stores STK_END + + call __FPSTACK_PUSH ; Push number into stack + rst 28h ; # Rom Calculator + defb 2Eh ; # STR$(x) + defb 38h ; # END CALC + call __FPSTACK_POP ; Recovers string parameters to A ED CB + + pop hl + ld (STK_END), hl ; Balance STK_END to avoid STR$ bug + + pop hl + ld (ATTR_T), hl ; Restores ATTR_T + + ex de, hl ; String position now in HL + + push bc + xor a ; Avoid the str to be FREED from heap + call __PRINT_STR + pop bc + inc bc + + jp RECLAIM2 ; Frees TMP Memory + + RECLAIM2 EQU 19E8h + + ENDP + +#line 108 "read8.bas" +#line 1 "read_restore.asm" + + ;; This implements READ & RESTORE functions + ;; Reads a new element from the DATA Address code + ;; Updates the DATA_ADDR read ptr for the next read + + ;; Data codification is 1 byte for type followed by data bytes + ;; Byte type is encoded as follows + +;; 00: End of data +;; 01: String +;; 02: Byte +;; 03: Ubyte +;; 04: Integer +;; 05: UInteger +;; 06: Long +;; 07: ULong +;; 08: Fixed +;; 09: Float + + ;; bit7 is set for a parameter-less function + ;; In that case, the next two bytes are the ptr of the function to jump + + +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 24 "read_restore.asm" +#line 1 "iload32.asm" + + ; __FASTCALL__ routine which + ; loads a 32 bits integer into DE,HL + ; stored at position pointed by POINTER HL + ; DE,HL <-- (HL) + +__ILOAD32: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + ex de, hl + ret + +#line 25 "read_restore.asm" +#line 1 "iloadf.asm" + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- ((HL)) + +__ILOADF: + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- (HL) + +__LOADF: ; Loads a 40 bits FP number from address pointed by HL + ld a, (hl) + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld c, (hl) + inc hl + ld b, (hl) + ret + +#line 26 "read_restore.asm" +#line 1 "ftof16reg.asm" + +#line 1 "ftou32reg.asm" + +#line 1 "neg32.asm" + +__ABS32: + bit 7, d + ret z + +__NEG32: ; Negates DEHL (Two's complement) + ld a, l + cpl + ld l, a + + ld a, h + cpl + ld h, a + + ld a, e + cpl + ld e, a + + ld a, d + cpl + ld d, a + + inc l + ret nz + + inc h + ret nz + + inc de + ret + +#line 2 "ftou32reg.asm" + +__FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + ; Output: DEHL 32 bit number (signed) + PROC + + LOCAL __IS_FLOAT + + or a + jr nz, __IS_FLOAT + ; Here if it is a ZX ROM Integer + + ld h, c + ld l, d + ld a, e ; Takes sign: FF = -, 0 = + + ld de, 0 + inc a + jp z, __NEG32 ; Negates if negative + ret + +__IS_FLOAT: ; Jumps here if it is a true floating point number + ld h, e + push hl ; Stores it for later (Contains Sign in H) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + ;ld a, c ; Get exponent + sub 128 ; Exponent -= 128 + jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + +__FTOU32REG_LOOP: + exx ; Shift C'B' E'D' << 1, output bit stays in Carry + sla d + rl e + rl b + rl c + + exx ; Shift DEHL << 1, inserting the carry on the right + rl l + rl h + rl e + rl d + + djnz __FTOU32REG_LOOP + +__FTOU32REG_END: + pop af ; Take the sign bit + or a ; Sets SGN bit to 1 if negative + jp m, __NEG32 ; Negates DEHL + + ret + + ENDP + + +__FTOU8: ; Converts float in C ED LH to Unsigned byte in A + call __FTOU32REG + ld a, l + ret + +#line 2 "ftof16reg.asm" + +__FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + + ld l, a ; Saves exponent for later + or d + or e + or b + or c + ld h, e + ret z ; Return if ZERO + + push hl ; Stores it for later (Contains sign in H, exponent in L) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + pop bc + + ld a, c ; Get exponent + sub 112 ; Exponent -= 128 + 16 + + push bc ; Saves sign in b again + + jp z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jp c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + 16 (we need to shift 16 bit more) + jp __FTOU32REG_LOOP ; proceed as an u32 integer + +#line 27 "read_restore.asm" +#line 1 "f16tofreg.asm" + + +#line 1 "u32tofreg.asm" + + +__I8TOFREG: + ld l, a + rlca + sbc a, a ; A = SGN(A) + ld h, a + ld e, a + ld d, a + +__I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) + ; to a Floating Point Number returned in (A ED CB) + + ld a, d + or a ; Test sign + + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __U32TOFREG ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + +__U8TOFREG: + ; Converts an unsigned 8 bit (A) to Floating point + ld l, a + ld h, 0 + ld e, h + ld d, h + +__U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in A ED CB + + PROC + + LOCAL __U32TOFREG_END + + ld a, d + or e + or h + or l + ld b, d + ld c, e ; Returns 00 0000 0000 if ZERO + ret z + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 128 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + +__U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG + exx + ld a, d ; B'C'D'E' == 0 ? + or e + or b + or c + jp z, __U32TOFREG_END ; We are done + + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry + rr c + rr d + rr e + exx + + rr e ; Shift EDCB >> 1, inserting the carry on the left + rr d + rr c + rr b + + inc l ; Increment exponent + jp __U32TOFREG_LOOP + + +__U32TOFREG_END: + exx + ld a, l ; Puts the exponent in a + res 7, e ; Sets the sign bit to 0 (positive) + + ret + ENDP + +#line 3 "f16tofreg.asm" + +__F16TOFREG: ; Converts a 16.16 signed fixed point (stored in DEHL) + ; to a Floating Point Number returned in (C ED CB) + PROC + + LOCAL __F16TOFREG2 + + ld a, d + or a ; Test sign + + jp p, __F16TOFREG2 ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __F16TOFREG2 ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + + +__F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in C DE HL + + ld a, d + or e + or h + or l + ld b, h + ld c, l + ret z ; Return 00 0000 0000 if 0 + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 112 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + jp __U32TOFREG_LOOP ; Proceed as an integer + + ENDP + +#line 28 "read_restore.asm" + + + + + + + + + + + + + + ;; Updates restore point to the given HL mem. address +__RESTORE: + PROC + LOCAL __DATA_ADDR + + ld (__DATA_ADDR), hl + ret + + ;; Reads a value from the DATA mem area and updates __DATA_ADDR ptr to the + ;; next item. On Out Of Data, restarts + ;; +__READ: + LOCAL read_restart, cont, cont2, table, no_func + LOCAL dynamic_cast, dynamic_cast2, dynamic_cast3, dynamic_cast4 + LOCAL _decode_table, coerce_to_int, coerce_to_int2, promote_to_i16 + LOCAL _from_i8, _from_u8 + LOCAL _from_i16, _from_u16 + LOCAL _from_i32, _from_u32 + LOCAL _from_fixed, __data_error + + push af ; type of data to read + ld hl, (__DATA_ADDR) +read_restart: + ld a, (hl) + or a ; 0 => OUT of data + jr nz, cont + ;; Signals out of data + + ld hl, __DATA__0 + ld (__DATA_ADDR), hl + jr read_restart ; Start again +cont: + and 0x80 + ld a, (hl) + push af + jp z, no_func ;; Loads data directly, not a function + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl +cont2: + ld de, dynamic_cast + push de ; ret address + jp (hl) ; "call (hl)" + + ;; Now tries to convert the given result to the expected type or raise an error +dynamic_cast: + exx + ex af, af' + pop af ; type READ + and 0x7F ; clear bit 7 + pop hl ; type requested by USER (type of the READ variable) + ld c, h ; save requested type (save it in register C) + cp h + exx + jr nz, dynamic_cast2 ; Types are identical? + ;; yes, they are + ex af, af' + ret + +dynamic_cast2: + cp 1 ; Requested a number, but read a string? + jr nz, dynamic_cast3 + call __MEM_FREE ; Frees str from memory + jr __data_error + +dynamic_cast3: + exx + ld b, a ; Read type + ld a, c ; Requested type + cp 1 + jr z, __data_error + cp b + jr c, dynamic_cast4 + ;; here the user expected type is "larger" than the read one + ld a, b + sub 2 + add a, a + ld l, a + ld h, 0 + ld de, _decode_table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl + ld a, c ; Requested type + exx + ret + +__data_error: + ;; When a data is read, but cannot be converted to the requested type + ;; that is, the user asked for a string and we read a number or vice versa + ld a, ERROR_InvalidArg + call __STOP ; The user expected a string, but read a number + xor a + ld h, a + ld l, a + ld e, a + ld d, a + ld b, a + ld c, a + ret + +_decode_table: + dw _from_i8 + dw _from_u8 + dw _from_i16 + dw _from_u16 + dw _from_i32 + dw _from_u32 + dw _from_fixed + +_from_i8: + cp 4 + jr nc, promote_to_i16 + ex af, af' + ret ;; Was from Byte to Ubyte + +promote_to_i16: + ex af, af' + ld l, a + rla + sbc a, a + ld h, a ; copy sgn to h + ex af, af' + jr _before_from_i16 + +_from_u8: + ex af, af' + ld l, a + ld h, 0 + ex af, af' + ;; Promoted to i16 + +_before_from_i16: +_from_i16: + cp 6 + ret c ;; from i16 to u16 + ;; Promote i16 to i32 + ex af, af' + ld a, h + rla + sbc a, a + ld e, a + ld d, a + ex af, af' +_from_i32: + cp 7 + ret z ;; From i32 to u32 + ret c ;; From u16 to i32 + cp 9 + jp z, __I32TOFREG +_from_u32: + cp 9 + jp z, __U32TOFREG + ex de, hl + ld hl, 0 + cp 8 + ret z +_from_fixed: ;; From fixed to float + jp __F16TOFREG +_from_u16: + ld de, 0 ; HL 0x0000 => 32 bits + jp _from_i32 + +dynamic_cast4: + ;; The user type is "shorter" than the read one + cp 8 ;; required type + jr c, before_to_int ;; required < fixed (f16) + ex af, af' + exx ;; Ok, we must convert from float to f16 + jp __FTOF16REG + +before_to_int: + ld a, b ;; read type + cp 8 ;; + jr nz, coerce_to_int ;; From float to int + ld a, c ;; user type + exx + ;; f16 to Long + ex de, hl + ld a, h + rla + sbc a, a + ld d, a + ld e, a + exx + jr coerce_to_int2 +coerce_to_int: + exx + ex af, af' + call __FTOU32REG + ex af, af' ; a contains user type + exx +coerce_to_int2: ; At this point we have an u/integer in hl + exx + cp 4 + ret nc ; Already done. Return the result + ld a, l ; Truncate to byte + ret + +no_func: + exx + ld de, dynamic_cast + push de ; Ret address + dec a ; 0 => string; 1, 2 => byte; 3, 4 => integer; 5, 6 => long, 7 => fixed; 8 => float + ld h, 0 + add a, a + ld l, a + ld de, table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl ; address to jump to + exx + inc hl + ret ; jp (sp) => jump to table[a - 1] + +table: + LOCAL __01_decode_string + LOCAL __02_decode_byte + LOCAL __03_decode_ubyte + LOCAL __04_decode_integer + LOCAL __05_decode_uinteger + LOCAL __06_decode_long + LOCAL __07_decode_ulong + LOCAL __08_decode_fixed + LOCAL __09_decode_float + + ;; 1 -> Decode string + ;; 2, 3 -> Decode Byte, UByte + ;; 4, 5 -> Decode Integer, UInteger + ;; 6, 7 -> Decode Long, ULong + ;; 8 -> Decode Fixed + ;; 9 -> Decode Float + dw __01_decode_string + dw __02_decode_byte + dw __03_decode_ubyte + dw __04_decode_integer + dw __05_decode_uinteger + dw __06_decode_long + dw __07_decode_ulong + dw __08_decode_fixed + dw __09_decode_float + +__01_decode_string: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl + jp __LOADSTR + +__02_decode_byte: +__03_decode_ubyte: + ld a, (hl) + inc hl + ld (__DATA_ADDR), hl + ret + +__04_decode_integer: +__05_decode_uinteger: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl + ex de, hl + ret + +__06_decode_long: +__07_decode_ulong: +__08_decode_fixed: + ld b, h + ld c, l + inc bc + inc bc + inc bc + inc bc + ld (__DATA_ADDR), bc + jp __ILOAD32 + +__09_decode_float: + call __LOADF + inc hl + ld (__DATA_ADDR), hl + ld h, a ; returns A in H; sets A free + ret + +__DATA_ADDR: ;; Stores current DATA ptr + dw __DATA__0 + ENDP + + + + + + + + + + +#line 109 "read8.bas" +#line 1 "sin.asm" + + + +SIN: ; Computes SIN using ROM FP-CALC + call __FPSTACK_PUSH + + rst 28h ; ROM CALC + defb 1Fh + defb 38h ; END CALC + + jp __FPSTACK_POP + +#line 110 "read8.bas" +#line 1 "storef.asm" + +__PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) + push de + ex de, hl ; DE <- HL + push ix + pop hl ; HL <- IX + add hl, de ; HL <- IX + HL + pop de + +__ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register + ex af, af' + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex af, af' + +__STOREF: ; Stores the given FP number in A EDCB at address HL + ld (hl), a + inc hl + ld (hl), e + inc hl + ld (hl), d + inc hl + ld (hl), c + inc hl + ld (hl), b + ret + +#line 111 "read8.bas" +#line 1 "tan.asm" + + + +TAN: ; Computes TAN using ROM FP-CALC + call __FPSTACK_PUSH + + rst 28h ; ROM CALC + defb 21h ; TAN + defb 38h ; END CALC + + jp __FPSTACK_POP + +#line 112 "read8.bas" + +ZXBASIC_USER_DATA: +_v: + DEFB 81h + DEFB 40h + DEFB 00h + DEFB 00h + DEFB 00h +_i: + DEFB 00 +_c: + DEFW 0000h + DEFB 05h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/read8.bas b/tests/functional/read8.bas new file mode 100644 index 000000000..c7340e4aa --- /dev/null +++ b/tests/functional/read8.bas @@ -0,0 +1,18 @@ +REM Error x is an array, not an scalar + +DIM v as Float = 1.5 + +RESTORE + +DATA 10, 25 * v, SIN(v) * tan(v)^2, PI * v + + +DIM c(3) as Float +FOR i = 1 TO 4: +READ c(1) +PRINT c(1) +NEXT i + + + + diff --git a/tests/functional/read9.asm b/tests/functional/read9.asm new file mode 100644 index 000000000..82d05f175 --- /dev/null +++ b/tests/functional/read9.asm @@ -0,0 +1,3013 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + call __PRINT_INIT + ld hl, __DATA__0 + call __RESTORE + xor a + ld (_i), a + jp __LABEL0 +__LABEL3: + ld a, 9 + call __READ + push bc + push de + push af + ld a, (_i) + ld l, a + ld h, 0 + push hl + ld hl, _c + call __ARRAY + pop af + pop de + pop bc + call __STOREF + ld a, (_i) + ld l, a + ld h, 0 + push hl + ld hl, _c + call __ARRAY + call __LOADF + call __PRINTF + call PRINT_EOL +__LABEL4: + ld a, (_i) + inc a + ld (_i), a +__LABEL0: + ld a, 3 + ld hl, (_i - 1) + cp h + jp nc, __LABEL3 +__LABEL2: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +___DATA__FUNCPTR__0: + ld a, (_v) + ld de, (_v + 1) + ld bc, (_v + 3) + ld hl, 00000h + push hl + ld hl, 00048h + push hl + ld h, 085h + push hl + call __MULF + jp ___DATA__FUNCPTR__0__leave +___DATA__FUNCPTR__0__leave: + ret +___DATA__FUNCPTR__1: + ld a, (_v) + ld de, (_v + 1) + ld bc, (_v + 3) + call SIN + push bc + push de + push af + ld a, (_v) + ld de, (_v + 1) + ld bc, (_v + 3) + call TAN + push bc + push de + push af + ld a, 082h + ld de, 00000h + ld bc, 00000h + call __POW + call __MULF + jp ___DATA__FUNCPTR__1__leave +___DATA__FUNCPTR__1__leave: + ret +___DATA__FUNCPTR__2: + ld a, (_v) + ld de, (_v + 1) + ld bc, (_v + 3) + ld hl, 0A2DAh + push hl + ld hl, 00F49h + push hl + ld h, 082h + push hl + call __MULF + jp ___DATA__FUNCPTR__2__leave +___DATA__FUNCPTR__2__leave: + ret +__DATA__0: + DEFB 3 + DEFB 10 + DEFB 89h + DEFW ___DATA__FUNCPTR__0 + DEFB 89h + DEFW ___DATA__FUNCPTR__1 + DEFB 89h + DEFW ___DATA__FUNCPTR__2 +__DATA__END: + DEFB 00h +#line 1 "array.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; ------------------------------------------------------------------- + ; Simple array Index routine + ; Number of total indexes dimensions - 1 at beginning of memory + ; HL = Start of array memory (First two bytes contains N-1 dimensions) + ; Dimension values on the stack, (top of the stack, highest dimension) + ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> + + ; For any array of N dimension A(aN-1, ..., a1, a0) + ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as + ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] +; What I will do here is to calculate the following sequence: + ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... + + +#line 1 "mul16.asm" + +__MUL16: ; Mutiplies HL with the last value stored into de stack + ; Works for both signed and unsigned + + PROC + + LOCAL __MUL16LOOP + LOCAL __MUL16NOADD + + ex de, hl + pop hl ; Return address + ex (sp), hl ; CALLEE caller convention + +;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand + ;; ld c, h + ;; ld a, l ; C,A => 1st Operand + ;; + ;; ld hl, 0 ; Accumulator + ;; ld b, 16 + ;; +;;__MUL16LOOP: + ;; sra c ; C,A >> 1 (Arithmetic) + ;; rra + ;; + ;; jr nc, __MUL16NOADD + ;; add hl, de + ;; +;;__MUL16NOADD: + ;; sla e + ;; rl d + ;; + ;; djnz __MUL16LOOP + +__MUL16_FAST: + ld b, 16 + ld a, d + ld c, e + ex de, hl + ld hl, 0 + +__MUL16LOOP: + add hl, hl ; hl << 1 + sla c + rla ; a,c << 1 + jp nc, __MUL16NOADD + add hl, de + +__MUL16NOADD: + djnz __MUL16LOOP + + ret ; Result in hl (16 lower bits) + + ENDP + +#line 20 "array.asm" + +#line 24 "/src/zxb/trunk/library-asm/array.asm" + +__ARRAY: + PROC + + LOCAL LOOP + LOCAL ARRAY_END + LOCAL RET_ADDRESS ; Stores return address + + ex (sp), hl ; Return address in HL, array address in the stack + ld (RET_ADDRESS + 1), hl ; Stores it for later + + exx + pop hl ; Will use H'L' as the pointer + ld c, (hl) ; Loads Number of dimensions from (hl) + inc hl + ld b, (hl) + inc hl ; Ready + exx + + ld hl, 0 ; BC = Offset "accumulator" + +#line 48 "/src/zxb/trunk/library-asm/array.asm" + +LOOP: + pop bc ; Get next index (Ai) from the stack + +#line 60 "/src/zxb/trunk/library-asm/array.asm" + + add hl, bc ; Adds current index + + exx ; Checks if B'C' = 0 + ld a, b ; Which means we must exit (last element is not multiplied by anything) + or c + jr z, ARRAY_END ; if B'Ci == 0 we are done + + ld e, (hl) ; Loads next dimension into D'E' + inc hl + ld d, (hl) + inc hl + push de + dec bc ; Decrements loop counter + exx + pop de ; DE = Max bound Number (i-th dimension) + +#line 80 "/src/zxb/trunk/library-asm/array.asm" + ;call __MUL16_FAST ; HL *= DE + call __FNMUL +#line 86 "/src/zxb/trunk/library-asm/array.asm" + jp LOOP + +ARRAY_END: + ld e, (hl) + inc hl + ld d, c ; C = 0 => DE = E = Element size + push hl + push de + exx + +#line 100 "/src/zxb/trunk/library-asm/array.asm" + LOCAL ARRAY_SIZE_LOOP + + ex de, hl + ld hl, 0 + pop bc + ld b, c +ARRAY_SIZE_LOOP: + add hl, de + djnz ARRAY_SIZE_LOOP + + ;; Even faster + ;pop bc + + ;ld d, h + ;ld e, l + + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, hl + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, hl + ;dec c + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, de + ;__ARRAY_FIN: +#line 131 "/src/zxb/trunk/library-asm/array.asm" + + pop de + add hl, de ; Adds element start + +RET_ADDRESS: + ld de, 0 + push de + ret ; HL = (Start of Elements + Offset) + + ;; Performs a faster multiply for little 16bit numbs + LOCAL __FNMUL, __FNMUL2 + +__FNMUL: + xor a + or d + jp nz, __MUL16_FAST + + or e + ex de, hl + ret z + + cp 33 + jp nc, __MUL16_FAST + + ld b, l + ld l, h ; HL = 0 + +__FNMUL2: + add hl, de + djnz __FNMUL2 + ret + + ENDP + +#line 120 "read9.bas" +#line 1 "iloadf.asm" + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- ((HL)) + +__ILOADF: + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- (HL) + +__LOADF: ; Loads a 40 bits FP number from address pointed by HL + ld a, (hl) + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld c, (hl) + inc hl + ld b, (hl) + ret + +#line 121 "read9.bas" +#line 1 "mulf.asm" + +#line 1 "stackf.asm" + + ; ------------------------------------------------------------- + ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC + ; ------------------------------------------------------------- + + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) + __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) + +__FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) + ; Second argument to push into the stack calculator is popped out of the stack + ; Since the caller routine also receives the parameters into the top of the stack + ; four bytes must be removed from SP before pop them out + + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK + exx + pop hl ; Caller-Caller return addr + exx + pop hl ; Caller return addr + + pop af + pop de + pop bc + + push hl ; Caller return addr + exx + push hl ; Caller-Caller return addr + exx + + jp __FPSTACK_PUSH + + +__FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK + ; This format is specified in the ZX 48K Manual + ; You can push a 16 bit signed integer as + ; 0 SS LL HH 0, being SS the sign and LL HH the low + ; and High byte respectively + ld a, h + rla ; sign to Carry + sbc a, a ; 0 if positive, FF if negative + ld e, a + ld d, l + ld c, h + xor a + ld b, a + jp __FPSTACK_PUSH +#line 2 "mulf.asm" + + ; ------------------------------------------------------------- + ; Floating point library using the FP ROM Calculator (ZX 48K) + ; All of them uses A EDCB registers as 1st paramter. + ; For binary operators, the 2n operator must be pushed into the + ; stack, in the order A DE BC. + ; + ; Uses CALLEE convention + ; ------------------------------------------------------------- + +__MULF: ; Multiplication + call __FPSTACK_PUSH2 + + ; ------------- ROM MUL + rst 28h + defb 04h ; + defb 38h; ; END CALC + + jp __FPSTACK_POP + +#line 122 "read9.bas" +#line 1 "pow.asm" + + + + ; ------------------------------------------------------------- + ; Floating point library using the FP ROM Calculator (ZX 48K) + + ; All of them uses A EDCB registers as 1st paramter. + ; For binary operators, the 2n operator must be pushed into the + ; stack, in the order A DE BC. + ; + ; Uses CALLEE convention + ; +; Operands comes swapped: + ; 1 st parameter is the BASE (A ED CB) + ; 2 nd parameter (Top of the stack) is Exponent + ; ------------------------------------------------------------- + +__POW: ; Exponentiation + PROC + + call __FPSTACK_PUSH2 + + ; ------------- ROM POW + rst 28h + defb 01h ; Exchange => 1, Base + defb 06h ; POW + defb 38h; ; END CALC + + jp __FPSTACK_POP + + ENDP + +#line 123 "read9.bas" +#line 1 "print.asm" + +; vim:ts=4:sw=4:et: + ; PRINT command routine + ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that + +#line 1 "sposn.asm" + + ; Printing positioning library. + PROC + LOCAL ECHO_E + +__LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. + ld de, (S_POSN) + ld hl, (MAXX) + or a + sbc hl, de + ex de, hl + ret + + +__SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. + ld hl, (MAXX) + or a + sbc hl, de + ld (S_POSN), hl ; saves it again + ret + + + ECHO_E EQU 23682 + MAXX EQU ECHO_E ; Max X position + 1 + MAXY EQU MAXX + 1 ; Max Y position + 1 + + S_POSN EQU 23688 + POSX EQU S_POSN ; Current POS X + POSY EQU S_POSN + 1 ; Current POS Y + + ENDP + +#line 6 "print.asm" +#line 1 "cls.asm" + + ; JUMPS directly to spectrum CLS + ; This routine does not clear lower screen + + ;CLS EQU 0DAFh + + ; Our faster implementation + + + +CLS: + PROC + + LOCAL COORDS + LOCAL __CLS_SCR + LOCAL ATTR_P + LOCAL SCREEN + + ld hl, 0 + ld (COORDS), hl + ld hl, 1821h + ld (S_POSN), hl +__CLS_SCR: + ld hl, SCREEN + ld (hl), 0 + ld d, h + ld e, l + inc de + ld bc, 6144 + ldir + + ; Now clear attributes + + ld a, (ATTR_P) + ld (hl), a + ld bc, 767 + ldir + ret + + COORDS EQU 23677 + SCREEN EQU 16384 ; Default start of the screen (can be changed) + ATTR_P EQU 23693 + ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address + + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines + ; to get the start of the screen + ENDP + +#line 7 "print.asm" +#line 1 "in_screen.asm" + + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 3 "in_screen.asm" + +__IN_SCREEN: + ; Returns NO carry if current coords (D, E) + ; are OUT of the screen limits (MAXX, MAXY) + + PROC + LOCAL __IN_SCREEN_ERR + + ld hl, MAXX + ld a, e + cp (hl) + jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + + ld a, d + inc hl + cp (hl) + ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + ;; ret + ret c ; Return if carry (OK) + +__IN_SCREEN_ERR: +__OUT_OF_SCREEN_ERR: + ; Jumps here if out of screen + ld a, ERROR_OutOfScreen + jp __STOP ; Saves error code and exits + + ENDP +#line 8 "print.asm" +#line 1 "table_jump.asm" + + +JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A + add a, a + +JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE + ld e, a + ld d, 0 + +JUMP_HL_PLUS_DE: ; Does JP (HL + DE) + add hl, de + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl +CALL_HL: + jp (hl) + +#line 9 "print.asm" +#line 1 "ink.asm" + + ; Sets ink color in ATTR_P permanently +; Parameter: Paper color in A register + +#line 1 "const.asm" + + ; Global constants + + P_FLAG EQU 23697 + FLAGS2 EQU 23681 + ATTR_P EQU 23693 ; permanet ATTRIBUTES + ATTR_T EQU 23695 ; temporary ATTRIBUTES + CHARS EQU 23606 ; Pointer to ROM/RAM Charset + UDG EQU 23675 ; Pointer to UDG Charset + MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars + +#line 5 "ink.asm" + +INK: + PROC + LOCAL __SET_INK + LOCAL __SET_INK2 + + ld de, ATTR_P + +__SET_INK: + cp 8 + jr nz, __SET_INK2 + + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + or 7 ; Set bits 0,1,2 to enable transparency + ld (de), a + ret + +__SET_INK2: + ; Another entry. This will set the ink color at location pointer by DE + and 7 ; # Gets color mod 8 + ld b, a ; Saves the color + ld a, (de) + and 0F8h ; Clears previous value + or b + ld (de), a + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + and 0F8h ; Reset bits 0,1,2 sign to disable transparency + ld (de), a ; Store new attr + ret + + ; Sets the INK color passed in A register in the ATTR_T variable +INK_TMP: + ld de, ATTR_T + jp __SET_INK + + ENDP + +#line 10 "print.asm" +#line 1 "paper.asm" + + ; Sets paper color in ATTR_P permanently +; Parameter: Paper color in A register + + + +PAPER: + PROC + LOCAL __SET_PAPER + LOCAL __SET_PAPER2 + + ld de, ATTR_P + +__SET_PAPER: + cp 8 + jr nz, __SET_PAPER2 + inc de + ld a, (de) + or 038h + ld (de), a + ret + + ; Another entry. This will set the paper color at location pointer by DE +__SET_PAPER2: + and 7 ; # Remove + rlca + rlca + rlca ; a *= 8 + + ld b, a ; Saves the color + ld a, (de) + and 0C7h ; Clears previous value + or b + ld (de), a + inc de ; Points to MASK_T or MASK_P accordingly + ld a, (de) + and 0C7h ; Resets bits 3,4,5 + ld (de), a + ret + + + ; Sets the PAPER color passed in A register in the ATTR_T variable +PAPER_TMP: + ld de, ATTR_T + jp __SET_PAPER + ENDP + +#line 11 "print.asm" +#line 1 "flash.asm" + + ; Sets flash flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +FLASH: + ld de, ATTR_P +__SET_FLASH: + ; Another entry. This will set the flash flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + ld b, a ; Saves the color + ld a, (de) + and 07Fh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the FLASH flag passed in A register in the ATTR_T variable +FLASH_TMP: + ld de, ATTR_T + jr __SET_FLASH + +#line 12 "print.asm" +#line 1 "bright.asm" + + ; Sets bright flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +BRIGHT: + ld de, ATTR_P + +__SET_BRIGHT: + ; Another entry. This will set the bright flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + rrca + ld b, a ; Saves the color + ld a, (de) + and 0BFh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable +BRIGHT_TMP: + ld de, ATTR_T + jr __SET_BRIGHT + +#line 13 "print.asm" +#line 1 "over.asm" + + ; Sets OVER flag in P_FLAG permanently +; Parameter: OVER flag in bit 0 of A register +#line 1 "copy_attr.asm" + + + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" + + + +COPY_ATTR: + ; Just copies current permanent attribs to temporal attribs + ; and sets print mode + PROC + + LOCAL INVERSE1 + LOCAL __REFRESH_TMP + + INVERSE1 EQU 02Fh + + ld hl, (ATTR_P) + ld (ATTR_T), hl + + ld hl, FLAGS2 + call __REFRESH_TMP + + ld hl, P_FLAG + call __REFRESH_TMP + + +__SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) + + + LOCAL TABLE + LOCAL CONT2 + + rra ; Over bit to carry + ld a, (FLAGS2) + rla ; Over bit in bit 1, Over2 bit in bit 2 + and 3 ; Only bit 0 and 1 (OVER flag) + + ld c, a + ld b, 0 + + ld hl, TABLE + add hl, bc + ld a, (hl) + ld (PRINT_MODE), a + + ld hl, (P_FLAG) + xor a ; NOP -> INVERSE0 + bit 2, l + jr z, CONT2 + ld a, INVERSE1 ; CPL -> INVERSE1 + +CONT2: + ld (INVERSE_MODE), a + ret + +TABLE: + nop ; NORMAL MODE + xor (hl) ; OVER 1 MODE + and (hl) ; OVER 2 MODE + or (hl) ; OVER 3 MODE + +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" + +__REFRESH_TMP: + ld a, (hl) + and 10101010b + ld c, a + rra + or c + ld (hl), a + ret + + ENDP + +#line 4 "over.asm" + + +OVER: + PROC + + ld c, a ; saves it for later + and 2 + ld hl, FLAGS2 + res 1, (HL) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 ; # Convert to 0/1 + add a, a; # Shift left 1 bit for permanent + + ld hl, P_FLAG + res 1, (hl) + or (hl) + ld (hl), a + ret + + ; Sets OVER flag in P_FLAG temporarily +OVER_TMP: + ld c, a ; saves it for later + and 2 ; gets bit 1; clears carry + rra + ld hl, FLAGS2 + res 0, (hl) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 + ld hl, P_FLAG + res 0, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 14 "print.asm" +#line 1 "inverse.asm" + + ; Sets INVERSE flag in P_FLAG permanently +; Parameter: INVERSE flag in bit 0 of A register + + + +INVERSE: + PROC + + and 1 ; # Convert to 0/1 + add a, a; # Shift left 3 bits for permanent + add a, a + add a, a + ld hl, P_FLAG + res 3, (hl) + or (hl) + ld (hl), a + ret + + ; Sets INVERSE flag in P_FLAG temporarily +INVERSE_TMP: + and 1 + add a, a + add a, a; # Shift left 2 bits for temporary + ld hl, P_FLAG + res 2, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 15 "print.asm" +#line 1 "bold.asm" + + ; Sets BOLD flag in P_FLAG permanently +; Parameter: BOLD flag in bit 0 of A register + + +BOLD: + PROC + + and 1 + rlca + rlca + rlca + ld hl, FLAGS2 + res 3, (HL) + or (hl) + ld (hl), a + ret + + ; Sets BOLD flag in P_FLAG temporarily +BOLD_TMP: + and 1 + rlca + rlca + ld hl, FLAGS2 + res 2, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 16 "print.asm" +#line 1 "italic.asm" + + ; Sets ITALIC flag in P_FLAG permanently +; Parameter: ITALIC flag in bit 0 of A register + + +ITALIC: + PROC + + and 1 + rrca + rrca + rrca + ld hl, FLAGS2 + res 5, (HL) + or (hl) + ld (hl), a + ret + + ; Sets ITALIC flag in P_FLAG temporarily +ITALIC_TMP: + and 1 + rrca + rrca + rrca + rrca + ld hl, FLAGS2 + res 4, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 17 "print.asm" + +#line 1 "attr.asm" + + ; Attribute routines +; vim:ts=4:et:sw: + + + + + + + +__ATTR_ADDR: + ; calc start address in DE (as (32 * d) + e) + ; Contributed by Santiago Romero at http://www.speccy.org + ld h, 0 ; 7 T-States + ld a, d ; 4 T-States + add a, a ; a * 2 ; 4 T-States + add a, a ; a * 4 ; 4 T-States + ld l, a ; HL = A * 4 ; 4 T-States + + add hl, hl ; HL = A * 8 ; 15 T-States + add hl, hl ; HL = A * 16 ; 15 T-States + add hl, hl ; HL = A * 32 ; 15 T-States + + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) + add hl, de + + ld de, (SCREEN_ADDR) ; Adds the screen address + add hl, de + + ; Return current screen address in HL + ret + + + ; Sets the attribute at a given screen coordinate (D, E). + ; The attribute is taken from the ATTR_T memory variable + ; Used by PRINT routines +SET_ATTR: + + ; Checks for valid coords + call __IN_SCREEN + ret nc + +__SET_ATTR: + ; Internal __FASTCALL__ Entry used by printing routines + PROC + + call __ATTR_ADDR + ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T + + ld a, d + and (hl) + ld c, a ; C = current screen color, masked + + ld a, d + cpl ; Negate mask + and e ; Mask current attributes + or c ; Mix them + ld (hl), a ; Store result in screen + + ret + + ENDP + + +#line 19 "print.asm" + + ; Putting a comment starting with @INIT
+ ; will make the compiler to add a CALL to
+ ; It is useful for initialization routines. + + +__PRINT_INIT: ; To be called before program starts (initializes library) + PROC + + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + + ld hl, 1821h + ld (MAXX), hl ; Sets current maxX and maxY + + xor a + ld (FLAGS2), a + + ret + + +__PRINTCHAR: ; Print character store in accumulator (A register) + ; Modifies H'L', B'C', A'F', D'E', A + + LOCAL PO_GR_1 + + LOCAL __PRCHAR + LOCAL __PRINT_CONT + LOCAL __PRINT_CONT2 + LOCAL __PRINT_JUMP + LOCAL __SRCADDR + LOCAL __PRINT_UDG + LOCAL __PRGRAPH + LOCAL __PRINT_START + + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 + +__PRINT_JUMP: + jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively + +__PRINT_START: + cp ' ' + jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones + + exx ; Switch to alternative registers + ex af, af' ; Saves a value (char to print) for later + + call __LOAD_S_POSN + + ; At this point we have the new coord + ld hl, (SCREEN_ADDR) + + ld a, d + ld c, a ; Saves it for later + + and 0F8h ; Masks 3 lower bit ; zy + ld d, a + + ld a, c ; Recovers it + and 07h ; MOD 7 ; y1 + rrca + rrca + rrca + + or e + ld e, a + add hl, de ; HL = Screen address + DE + ex de, hl ; DE = Screen address + + ex af, af' + + cp 80h ; Is it an UDG or a ? + jp c, __SRCADDR + + cp 90h + jp nc, __PRINT_UDG + + ; Print a 8 bit pattern (80h to 8Fh) + + ld b, a + call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 + ld hl, MEM0 + jp __PRGRAPH + + PO_GR_1 EQU 0B38h + +__PRINT_UDG: + sub 90h ; Sub ASC code + ld bc, (UDG) + jp __PRGRAPH0 + + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source +__SRCADDR: + ld bc, (CHARS) + +__PRGRAPH0: + add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org + ld l, a + ld h, 0 ; HL = a * 2 (accumulator) + add hl, hl + add hl, hl ; HL = a * 8 + add hl, bc ; HL = CHARS address + +__PRGRAPH: + ex de, hl ; HL = Write Address, DE = CHARS address + bit 2, (iy + $47) + call nz, __BOLD + bit 4, (iy + $47) + call nz, __ITALIC + ld b, 8 ; 8 bytes per char +__PRCHAR: + ld a, (de) ; DE *must* be ALWAYS source, and HL destiny + +PRINT_MODE: ; Which operation is used to write on the screen + ; Set it with: + ; LD A, + ; LD (PRINT_MODE), A + ; + ; Available opertions: + ; NORMAL: 0h --> NOP ; OVER 0 + ; XOR : AEh --> XOR (HL) ; OVER 1 + ; OR : B6h --> OR (HL) ; PUTSPRITE + ; AND : A6h --> AND (HL) ; PUTMASK + nop ; + +INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 + nop ; 2F -> CPL -> INVERSE 1 + + ld (hl), a + + inc de + inc h ; Next line + djnz __PRCHAR + + call __LOAD_S_POSN + push de + call __SET_ATTR + pop de + inc e ; COL = COL + 1 + ld hl, (MAXX) + ld a, e + dec l ; l = MAXX + cp l ; Lower than max? + jp c, __PRINT_CONT; Nothing to do + call __PRINT_EOL1 + exx ; counteracts __PRINT_EOL1 exx + jp __PRINT_CONT2 + +__PRINT_CONT: + call __SAVE_S_POSN + +__PRINT_CONT2: + exx + ret + + ; ------------- SPECIAL CHARS (< 32) ----------------- + +__PRINT_SPECIAL: ; Jumps here if it is a special char + exx + ld hl, __PRINT_TABLE + jp JUMP_HL_PLUS_2A + + +PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence + exx + +__PRINT_0Dh: ; Called WHEN printing CHR$(13) + call __LOAD_S_POSN + +__PRINT_EOL1: ; Another entry called from PRINT when next line required + ld e, 0 + +__PRINT_EOL2: + ld a, d + inc a + +__PRINT_AT1_END: + ld hl, (MAXY) + cp l + jr c, __PRINT_EOL_END ; Carry if (MAXY) < d + xor a + +__PRINT_EOL_END: + ld d, a + +__PRINT_AT2_END: + call __SAVE_S_POSN + exx + ret + +__PRINT_COM: + exx + push hl + push de + push bc + call PRINT_COMMA + pop bc + pop de + pop hl + ret + +__PRINT_TAB: + ld hl, __PRINT_TAB1 + jp __PRINT_SET_STATE + +__PRINT_TAB1: + ld (MEM0), a + ld hl, __PRINT_TAB2 + ld (PRINT_JUMP_STATE), hl + ret + +__PRINT_TAB2: + ld a, (MEM0) ; Load tab code (ignore the current one) + push hl + push de + push bc + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + call PRINT_TAB + pop bc + pop de + pop hl + ret + +__PRINT_NOP: +__PRINT_RESTART: + ld hl, __PRINT_START + jp __PRINT_SET_STATE + +__PRINT_AT: + ld hl, __PRINT_AT1 + +__PRINT_SET_STATE: + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + exx + ret + +__PRINT_AT1: ; Jumps here if waiting for 1st parameter + exx + ld hl, __PRINT_AT2 + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + jp __PRINT_AT1_END + +__PRINT_AT2: + exx + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + ld e, a + ld hl, (MAXX) + cp (hl) + jr c, __PRINT_AT2_END + jr __PRINT_EOL1 + +__PRINT_DEL: + call __LOAD_S_POSN ; Gets current screen position + dec e + ld a, -1 + cp e + jp nz, __PRINT_AT2_END + ld hl, (MAXX) + ld e, l + dec e + dec e + dec d + cp d + jp nz, __PRINT_AT2_END + ld d, h + dec d + jp __PRINT_AT2_END + +__PRINT_INK: + ld hl, __PRINT_INK2 + jp __PRINT_SET_STATE + +__PRINT_INK2: + exx + call INK_TMP + jp __PRINT_RESTART + +__PRINT_PAP: + ld hl, __PRINT_PAP2 + jp __PRINT_SET_STATE + +__PRINT_PAP2: + exx + call PAPER_TMP + jp __PRINT_RESTART + +__PRINT_FLA: + ld hl, __PRINT_FLA2 + jp __PRINT_SET_STATE + +__PRINT_FLA2: + exx + call FLASH_TMP + jp __PRINT_RESTART + +__PRINT_BRI: + ld hl, __PRINT_BRI2 + jp __PRINT_SET_STATE + +__PRINT_BRI2: + exx + call BRIGHT_TMP + jp __PRINT_RESTART + +__PRINT_INV: + ld hl, __PRINT_INV2 + jp __PRINT_SET_STATE + +__PRINT_INV2: + exx + call INVERSE_TMP + jp __PRINT_RESTART + +__PRINT_OVR: + ld hl, __PRINT_OVR2 + jp __PRINT_SET_STATE + +__PRINT_OVR2: + exx + call OVER_TMP + jp __PRINT_RESTART + +__PRINT_BOLD: + ld hl, __PRINT_BOLD2 + jp __PRINT_SET_STATE + +__PRINT_BOLD2: + exx + call BOLD_TMP + jp __PRINT_RESTART + +__PRINT_ITA: + ld hl, __PRINT_ITA2 + jp __PRINT_SET_STATE + +__PRINT_ITA2: + exx + call ITALIC_TMP + jp __PRINT_RESTART + + +__BOLD: + push hl + ld hl, MEM0 + ld b, 8 +__BOLD_LOOP: + ld a, (de) + ld c, a + rlca + or c + ld (hl), a + inc hl + inc de + djnz __BOLD_LOOP + pop hl + ld de, MEM0 + ret + + +__ITALIC: + push hl + ld hl, MEM0 + ex de, hl + ld bc, 8 + ldir + ld hl, MEM0 + srl (hl) + inc hl + srl (hl) + inc hl + srl (hl) + inc hl + inc hl + inc hl + sla (hl) + inc hl + sla (hl) + inc hl + sla (hl) + pop hl + ld de, MEM0 + ret + +PRINT_COMMA: + call __LOAD_S_POSN + ld a, e + and 16 + add a, 16 + +PRINT_TAB: + PROC + LOCAL LOOP, CONTINUE + + inc a + call __LOAD_S_POSN ; e = current row + ld d, a + ld a, e + cp 21h + jr nz, CONTINUE + ld e, -1 +CONTINUE: + ld a, d + inc e + sub e ; A = A - E + and 31 ; + ret z ; Already at position E + ld b, a +LOOP: + ld a, ' ' + call __PRINTCHAR + djnz LOOP + ret + ENDP + +PRINT_AT: ; CHanges cursor to ROW, COL + ; COL in A register + ; ROW in stack + + pop hl ; Ret address + ex (sp), hl ; callee H = ROW + ld l, a + ex de, hl + + call __IN_SCREEN + ret nc ; Return if out of screen + + jp __SAVE_S_POSN + + LOCAL __PRINT_COM + LOCAL __BOLD + LOCAL __BOLD_LOOP + LOCAL __ITALIC + LOCAL __PRINT_EOL1 + LOCAL __PRINT_EOL2 + LOCAL __PRINT_AT1 + LOCAL __PRINT_AT2 + LOCAL __PRINT_AT2_END + LOCAL __PRINT_BOLD + LOCAL __PRINT_BOLD2 + LOCAL __PRINT_ITA + LOCAL __PRINT_ITA2 + LOCAL __PRINT_INK + LOCAL __PRINT_PAP + LOCAL __PRINT_SET_STATE + LOCAL __PRINT_TABLE + LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 + +__PRINT_TABLE: ; Jump table for 0 .. 22 codes + + DW __PRINT_NOP ; 0 + DW __PRINT_NOP ; 1 + DW __PRINT_NOP ; 2 + DW __PRINT_NOP ; 3 + DW __PRINT_NOP ; 4 + DW __PRINT_NOP ; 5 + DW __PRINT_COM ; 6 COMMA + DW __PRINT_NOP ; 7 + DW __PRINT_DEL ; 8 DEL + DW __PRINT_NOP ; 9 + DW __PRINT_NOP ; 10 + DW __PRINT_NOP ; 11 + DW __PRINT_NOP ; 12 + DW __PRINT_0Dh ; 13 + DW __PRINT_BOLD ; 14 + DW __PRINT_ITA ; 15 + DW __PRINT_INK ; 16 + DW __PRINT_PAP ; 17 + DW __PRINT_FLA ; 18 + DW __PRINT_BRI ; 19 + DW __PRINT_INV ; 20 + DW __PRINT_OVR ; 21 + DW __PRINT_AT ; 22 AT + DW __PRINT_TAB ; 23 TAB + + ENDP + + +#line 124 "read9.bas" +#line 1 "printf.asm" + +#line 1 "printstr.asm" + + + + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 5 "printstr.asm" + + ; PRINT command routine + ; Prints string pointed by HL + +PRINT_STR: +__PRINTSTR: ; __FASTCALL__ Entry to print_string + PROC + LOCAL __PRINT_STR_LOOP + LOCAL __PRINT_STR_END + + ld d, a ; Saves A reg (Flag) for later + + ld a, h + or l + ret z ; Return if the pointer is NULL + + push hl + + ld c, (hl) + inc hl + ld b, (hl) + inc hl ; BC = LEN(a$); HL = &a$ + +__PRINT_STR_LOOP: + ld a, b + or c + jr z, __PRINT_STR_END ; END if BC (counter = 0) + + ld a, (hl) + call __PRINTCHAR + inc hl + dec bc + jp __PRINT_STR_LOOP + +__PRINT_STR_END: + pop hl + ld a, d ; Recovers A flag + or a ; If not 0 this is a temporary string. Free it + ret z + jp __MEM_FREE ; Frees str from heap and return from there + +__PRINT_STR: + ; Fastcall Entry + ; It ONLY prints strings + ; HL = String start + ; BC = String length (Number of chars) + push hl ; Push str address for later + ld d, a ; Saves a FLAG + jp __PRINT_STR_LOOP + + ENDP + +#line 2 "printf.asm" + + + +__PRINTF: ; Prints a Fixed point Number stored in C ED LH + PROC + + LOCAL RECLAIM2 + LOCAL STK_END + STK_END EQU 5C65h + + ld hl, (ATTR_T) + push hl ; Saves ATTR_T since BUG ROM changes it + + ld hl, (STK_END) + push hl ; Stores STK_END + + call __FPSTACK_PUSH ; Push number into stack + rst 28h ; # Rom Calculator + defb 2Eh ; # STR$(x) + defb 38h ; # END CALC + call __FPSTACK_POP ; Recovers string parameters to A ED CB + + pop hl + ld (STK_END), hl ; Balance STK_END to avoid STR$ bug + + pop hl + ld (ATTR_T), hl ; Restores ATTR_T + + ex de, hl ; String position now in HL + + push bc + xor a ; Avoid the str to be FREED from heap + call __PRINT_STR + pop bc + inc bc + + jp RECLAIM2 ; Frees TMP Memory + + RECLAIM2 EQU 19E8h + + ENDP + +#line 125 "read9.bas" +#line 1 "read_restore.asm" + + ;; This implements READ & RESTORE functions + ;; Reads a new element from the DATA Address code + ;; Updates the DATA_ADDR read ptr for the next read + + ;; Data codification is 1 byte for type followed by data bytes + ;; Byte type is encoded as follows + +;; 00: End of data +;; 01: String +;; 02: Byte +;; 03: Ubyte +;; 04: Integer +;; 05: UInteger +;; 06: Long +;; 07: ULong +;; 08: Fixed +;; 09: Float + + ;; bit7 is set for a parameter-less function + ;; In that case, the next two bytes are the ptr of the function to jump + + +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 24 "read_restore.asm" +#line 1 "iload32.asm" + + ; __FASTCALL__ routine which + ; loads a 32 bits integer into DE,HL + ; stored at position pointed by POINTER HL + ; DE,HL <-- (HL) + +__ILOAD32: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + ex de, hl + ret + +#line 25 "read_restore.asm" + +#line 1 "ftof16reg.asm" + +#line 1 "ftou32reg.asm" + +#line 1 "neg32.asm" + +__ABS32: + bit 7, d + ret z + +__NEG32: ; Negates DEHL (Two's complement) + ld a, l + cpl + ld l, a + + ld a, h + cpl + ld h, a + + ld a, e + cpl + ld e, a + + ld a, d + cpl + ld d, a + + inc l + ret nz + + inc h + ret nz + + inc de + ret + +#line 2 "ftou32reg.asm" + +__FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + ; Output: DEHL 32 bit number (signed) + PROC + + LOCAL __IS_FLOAT + + or a + jr nz, __IS_FLOAT + ; Here if it is a ZX ROM Integer + + ld h, c + ld l, d + ld a, e ; Takes sign: FF = -, 0 = + + ld de, 0 + inc a + jp z, __NEG32 ; Negates if negative + ret + +__IS_FLOAT: ; Jumps here if it is a true floating point number + ld h, e + push hl ; Stores it for later (Contains Sign in H) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + ;ld a, c ; Get exponent + sub 128 ; Exponent -= 128 + jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + +__FTOU32REG_LOOP: + exx ; Shift C'B' E'D' << 1, output bit stays in Carry + sla d + rl e + rl b + rl c + + exx ; Shift DEHL << 1, inserting the carry on the right + rl l + rl h + rl e + rl d + + djnz __FTOU32REG_LOOP + +__FTOU32REG_END: + pop af ; Take the sign bit + or a ; Sets SGN bit to 1 if negative + jp m, __NEG32 ; Negates DEHL + + ret + + ENDP + + +__FTOU8: ; Converts float in C ED LH to Unsigned byte in A + call __FTOU32REG + ld a, l + ret + +#line 2 "ftof16reg.asm" + +__FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + + ld l, a ; Saves exponent for later + or d + or e + or b + or c + ld h, e + ret z ; Return if ZERO + + push hl ; Stores it for later (Contains sign in H, exponent in L) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + pop bc + + ld a, c ; Get exponent + sub 112 ; Exponent -= 128 + 16 + + push bc ; Saves sign in b again + + jp z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jp c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + 16 (we need to shift 16 bit more) + jp __FTOU32REG_LOOP ; proceed as an u32 integer + +#line 27 "read_restore.asm" +#line 1 "f16tofreg.asm" + + +#line 1 "u32tofreg.asm" + + +__I8TOFREG: + ld l, a + rlca + sbc a, a ; A = SGN(A) + ld h, a + ld e, a + ld d, a + +__I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) + ; to a Floating Point Number returned in (A ED CB) + + ld a, d + or a ; Test sign + + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __U32TOFREG ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + +__U8TOFREG: + ; Converts an unsigned 8 bit (A) to Floating point + ld l, a + ld h, 0 + ld e, h + ld d, h + +__U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in A ED CB + + PROC + + LOCAL __U32TOFREG_END + + ld a, d + or e + or h + or l + ld b, d + ld c, e ; Returns 00 0000 0000 if ZERO + ret z + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 128 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + +__U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG + exx + ld a, d ; B'C'D'E' == 0 ? + or e + or b + or c + jp z, __U32TOFREG_END ; We are done + + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry + rr c + rr d + rr e + exx + + rr e ; Shift EDCB >> 1, inserting the carry on the left + rr d + rr c + rr b + + inc l ; Increment exponent + jp __U32TOFREG_LOOP + + +__U32TOFREG_END: + exx + ld a, l ; Puts the exponent in a + res 7, e ; Sets the sign bit to 0 (positive) + + ret + ENDP + +#line 3 "f16tofreg.asm" + +__F16TOFREG: ; Converts a 16.16 signed fixed point (stored in DEHL) + ; to a Floating Point Number returned in (C ED CB) + PROC + + LOCAL __F16TOFREG2 + + ld a, d + or a ; Test sign + + jp p, __F16TOFREG2 ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __F16TOFREG2 ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + + +__F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in C DE HL + + ld a, d + or e + or h + or l + ld b, h + ld c, l + ret z ; Return 00 0000 0000 if 0 + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 112 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + jp __U32TOFREG_LOOP ; Proceed as an integer + + ENDP + +#line 28 "read_restore.asm" + + + + + + + + + + + + + + ;; Updates restore point to the given HL mem. address +__RESTORE: + PROC + LOCAL __DATA_ADDR + + ld (__DATA_ADDR), hl + ret + + ;; Reads a value from the DATA mem area and updates __DATA_ADDR ptr to the + ;; next item. On Out Of Data, restarts + ;; +__READ: + LOCAL read_restart, cont, cont2, table, no_func + LOCAL dynamic_cast, dynamic_cast2, dynamic_cast3, dynamic_cast4 + LOCAL _decode_table, coerce_to_int, coerce_to_int2, promote_to_i16 + LOCAL _from_i8, _from_u8 + LOCAL _from_i16, _from_u16 + LOCAL _from_i32, _from_u32 + LOCAL _from_fixed, __data_error + + push af ; type of data to read + ld hl, (__DATA_ADDR) +read_restart: + ld a, (hl) + or a ; 0 => OUT of data + jr nz, cont + ;; Signals out of data + + ld hl, __DATA__0 + ld (__DATA_ADDR), hl + jr read_restart ; Start again +cont: + and 0x80 + ld a, (hl) + push af + jp z, no_func ;; Loads data directly, not a function + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl +cont2: + ld de, dynamic_cast + push de ; ret address + jp (hl) ; "call (hl)" + + ;; Now tries to convert the given result to the expected type or raise an error +dynamic_cast: + exx + ex af, af' + pop af ; type READ + and 0x7F ; clear bit 7 + pop hl ; type requested by USER (type of the READ variable) + ld c, h ; save requested type (save it in register C) + cp h + exx + jr nz, dynamic_cast2 ; Types are identical? + ;; yes, they are + ex af, af' + ret + +dynamic_cast2: + cp 1 ; Requested a number, but read a string? + jr nz, dynamic_cast3 + call __MEM_FREE ; Frees str from memory + jr __data_error + +dynamic_cast3: + exx + ld b, a ; Read type + ld a, c ; Requested type + cp 1 + jr z, __data_error + cp b + jr c, dynamic_cast4 + ;; here the user expected type is "larger" than the read one + ld a, b + sub 2 + add a, a + ld l, a + ld h, 0 + ld de, _decode_table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl + ld a, c ; Requested type + exx + ret + +__data_error: + ;; When a data is read, but cannot be converted to the requested type + ;; that is, the user asked for a string and we read a number or vice versa + ld a, ERROR_InvalidArg + call __STOP ; The user expected a string, but read a number + xor a + ld h, a + ld l, a + ld e, a + ld d, a + ld b, a + ld c, a + ret + +_decode_table: + dw _from_i8 + dw _from_u8 + dw _from_i16 + dw _from_u16 + dw _from_i32 + dw _from_u32 + dw _from_fixed + +_from_i8: + cp 4 + jr nc, promote_to_i16 + ex af, af' + ret ;; Was from Byte to Ubyte + +promote_to_i16: + ex af, af' + ld l, a + rla + sbc a, a + ld h, a ; copy sgn to h + ex af, af' + jr _before_from_i16 + +_from_u8: + ex af, af' + ld l, a + ld h, 0 + ex af, af' + ;; Promoted to i16 + +_before_from_i16: +_from_i16: + cp 6 + ret c ;; from i16 to u16 + ;; Promote i16 to i32 + ex af, af' + ld a, h + rla + sbc a, a + ld e, a + ld d, a + ex af, af' +_from_i32: + cp 7 + ret z ;; From i32 to u32 + ret c ;; From u16 to i32 + cp 9 + jp z, __I32TOFREG +_from_u32: + cp 9 + jp z, __U32TOFREG + ex de, hl + ld hl, 0 + cp 8 + ret z +_from_fixed: ;; From fixed to float + jp __F16TOFREG +_from_u16: + ld de, 0 ; HL 0x0000 => 32 bits + jp _from_i32 + +dynamic_cast4: + ;; The user type is "shorter" than the read one + cp 8 ;; required type + jr c, before_to_int ;; required < fixed (f16) + ex af, af' + exx ;; Ok, we must convert from float to f16 + jp __FTOF16REG + +before_to_int: + ld a, b ;; read type + cp 8 ;; + jr nz, coerce_to_int ;; From float to int + ld a, c ;; user type + exx + ;; f16 to Long + ex de, hl + ld a, h + rla + sbc a, a + ld d, a + ld e, a + exx + jr coerce_to_int2 +coerce_to_int: + exx + ex af, af' + call __FTOU32REG + ex af, af' ; a contains user type + exx +coerce_to_int2: ; At this point we have an u/integer in hl + exx + cp 4 + ret nc ; Already done. Return the result + ld a, l ; Truncate to byte + ret + +no_func: + exx + ld de, dynamic_cast + push de ; Ret address + dec a ; 0 => string; 1, 2 => byte; 3, 4 => integer; 5, 6 => long, 7 => fixed; 8 => float + ld h, 0 + add a, a + ld l, a + ld de, table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl ; address to jump to + exx + inc hl + ret ; jp (sp) => jump to table[a - 1] + +table: + LOCAL __01_decode_string + LOCAL __02_decode_byte + LOCAL __03_decode_ubyte + LOCAL __04_decode_integer + LOCAL __05_decode_uinteger + LOCAL __06_decode_long + LOCAL __07_decode_ulong + LOCAL __08_decode_fixed + LOCAL __09_decode_float + + ;; 1 -> Decode string + ;; 2, 3 -> Decode Byte, UByte + ;; 4, 5 -> Decode Integer, UInteger + ;; 6, 7 -> Decode Long, ULong + ;; 8 -> Decode Fixed + ;; 9 -> Decode Float + dw __01_decode_string + dw __02_decode_byte + dw __03_decode_ubyte + dw __04_decode_integer + dw __05_decode_uinteger + dw __06_decode_long + dw __07_decode_ulong + dw __08_decode_fixed + dw __09_decode_float + +__01_decode_string: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl + jp __LOADSTR + +__02_decode_byte: +__03_decode_ubyte: + ld a, (hl) + inc hl + ld (__DATA_ADDR), hl + ret + +__04_decode_integer: +__05_decode_uinteger: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl + ex de, hl + ret + +__06_decode_long: +__07_decode_ulong: +__08_decode_fixed: + ld b, h + ld c, l + inc bc + inc bc + inc bc + inc bc + ld (__DATA_ADDR), bc + jp __ILOAD32 + +__09_decode_float: + call __LOADF + inc hl + ld (__DATA_ADDR), hl + ld h, a ; returns A in H; sets A free + ret + +__DATA_ADDR: ;; Stores current DATA ptr + dw __DATA__0 + ENDP + + + + + + + + + + +#line 126 "read9.bas" +#line 1 "sin.asm" + + + +SIN: ; Computes SIN using ROM FP-CALC + call __FPSTACK_PUSH + + rst 28h ; ROM CALC + defb 1Fh + defb 38h ; END CALC + + jp __FPSTACK_POP + +#line 127 "read9.bas" +#line 1 "storef.asm" + +__PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) + push de + ex de, hl ; DE <- HL + push ix + pop hl ; HL <- IX + add hl, de ; HL <- IX + HL + pop de + +__ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register + ex af, af' + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex af, af' + +__STOREF: ; Stores the given FP number in A EDCB at address HL + ld (hl), a + inc hl + ld (hl), e + inc hl + ld (hl), d + inc hl + ld (hl), c + inc hl + ld (hl), b + ret + +#line 128 "read9.bas" +#line 1 "tan.asm" + + + +TAN: ; Computes TAN using ROM FP-CALC + call __FPSTACK_PUSH + + rst 28h ; ROM CALC + defb 21h ; TAN + defb 38h ; END CALC + + jp __FPSTACK_POP + +#line 129 "read9.bas" + +ZXBASIC_USER_DATA: +_v: + DEFB 81h + DEFB 40h + DEFB 00h + DEFB 00h + DEFB 00h +_i: + DEFB 00 +_c: + DEFW 0000h + DEFB 05h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/read9.bas b/tests/functional/read9.bas new file mode 100644 index 000000000..f95a7064f --- /dev/null +++ b/tests/functional/read9.bas @@ -0,0 +1,20 @@ +REM Error x is an array, not an scalar + +DIM v as Float = 1.5 + +RESTORE + +DATA 10, 25 * v, SIN(v) * tan(v)^2, PI * v + +DIM i as UByte + + +DIM c(3) as Float +FOR i = 0 TO 3: +READ c(i) +PRINT c(i) +NEXT i + + + + diff --git a/tests/functional/readokdown.asm b/tests/functional/readokdown.asm new file mode 100644 index 000000000..0ff2ed8aa --- /dev/null +++ b/tests/functional/readokdown.asm @@ -0,0 +1,3277 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + call __PRINT_INIT + ld hl, __DATA__0 + call __RESTORE + ld a, 2 + call __READ + ld (_i8), a + call __PRINTI8 + call PRINT_EOL + ld hl, __DATA__0 + call __RESTORE + ld a, 3 + call __READ + ld (_u8), a + call __PRINTU8 + call PRINT_EOL + ld hl, __DATA__0 + call __RESTORE + ld a, 4 + call __READ + ld (_i16), hl + call __PRINTI16 + call PRINT_EOL + ld hl, __DATA__0 + call __RESTORE + ld a, 5 + call __READ + ld (_u16), hl + call __PRINTU16 + call PRINT_EOL + ld hl, __DATA__0 + call __RESTORE + ld a, 6 + call __READ + ld (_i32), hl + ld (_i32 + 2), de + ld hl, (_i32) + ld de, (_i32 + 2) + call __PRINTI32 + call PRINT_EOL + ld hl, __DATA__0 + call __RESTORE + ld a, 7 + call __READ + ld (_u32), hl + ld (_u32 + 2), de + ld hl, (_u32) + ld de, (_u32 + 2) + call __PRINTU32 + call PRINT_EOL + ld hl, __DATA__0 + call __RESTORE + ld a, 8 + call __READ + ld (_f16), hl + ld (_f16 + 2), de + ld hl, (_f16) + ld de, (_f16 + 2) + call __PRINTF16 + call PRINT_EOL + ld hl, __DATA__0 + call __RESTORE + ld a, 9 + call __READ + ld hl, _flt + call __STOREF + ld a, (_flt) + ld de, (_flt + 1) + ld bc, (_flt + 3) + call __PRINTF + call PRINT_EOL + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__DATA__0: + DEFB 9 + DEFB 090h + DEFW 0E880h, 04627h +__DATA__END: + DEFB 00h +#line 1 "print.asm" + +; vim:ts=4:sw=4:et: + ; PRINT command routine + ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that + +#line 1 "sposn.asm" + + ; Printing positioning library. + PROC + LOCAL ECHO_E + +__LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. + ld de, (S_POSN) + ld hl, (MAXX) + or a + sbc hl, de + ex de, hl + ret + + +__SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. + ld hl, (MAXX) + or a + sbc hl, de + ld (S_POSN), hl ; saves it again + ret + + + ECHO_E EQU 23682 + MAXX EQU ECHO_E ; Max X position + 1 + MAXY EQU MAXX + 1 ; Max Y position + 1 + + S_POSN EQU 23688 + POSX EQU S_POSN ; Current POS X + POSY EQU S_POSN + 1 ; Current POS Y + + ENDP + +#line 6 "print.asm" +#line 1 "cls.asm" + + ; JUMPS directly to spectrum CLS + ; This routine does not clear lower screen + + ;CLS EQU 0DAFh + + ; Our faster implementation + + + +CLS: + PROC + + LOCAL COORDS + LOCAL __CLS_SCR + LOCAL ATTR_P + LOCAL SCREEN + + ld hl, 0 + ld (COORDS), hl + ld hl, 1821h + ld (S_POSN), hl +__CLS_SCR: + ld hl, SCREEN + ld (hl), 0 + ld d, h + ld e, l + inc de + ld bc, 6144 + ldir + + ; Now clear attributes + + ld a, (ATTR_P) + ld (hl), a + ld bc, 767 + ldir + ret + + COORDS EQU 23677 + SCREEN EQU 16384 ; Default start of the screen (can be changed) + ATTR_P EQU 23693 + ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address + + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines + ; to get the start of the screen + ENDP + +#line 7 "print.asm" +#line 1 "in_screen.asm" + + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 3 "in_screen.asm" + +__IN_SCREEN: + ; Returns NO carry if current coords (D, E) + ; are OUT of the screen limits (MAXX, MAXY) + + PROC + LOCAL __IN_SCREEN_ERR + + ld hl, MAXX + ld a, e + cp (hl) + jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + + ld a, d + inc hl + cp (hl) + ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + ;; ret + ret c ; Return if carry (OK) + +__IN_SCREEN_ERR: +__OUT_OF_SCREEN_ERR: + ; Jumps here if out of screen + ld a, ERROR_OutOfScreen + jp __STOP ; Saves error code and exits + + ENDP +#line 8 "print.asm" +#line 1 "table_jump.asm" + + +JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A + add a, a + +JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE + ld e, a + ld d, 0 + +JUMP_HL_PLUS_DE: ; Does JP (HL + DE) + add hl, de + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl +CALL_HL: + jp (hl) + +#line 9 "print.asm" +#line 1 "ink.asm" + + ; Sets ink color in ATTR_P permanently +; Parameter: Paper color in A register + +#line 1 "const.asm" + + ; Global constants + + P_FLAG EQU 23697 + FLAGS2 EQU 23681 + ATTR_P EQU 23693 ; permanet ATTRIBUTES + ATTR_T EQU 23695 ; temporary ATTRIBUTES + CHARS EQU 23606 ; Pointer to ROM/RAM Charset + UDG EQU 23675 ; Pointer to UDG Charset + MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars + +#line 5 "ink.asm" + +INK: + PROC + LOCAL __SET_INK + LOCAL __SET_INK2 + + ld de, ATTR_P + +__SET_INK: + cp 8 + jr nz, __SET_INK2 + + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + or 7 ; Set bits 0,1,2 to enable transparency + ld (de), a + ret + +__SET_INK2: + ; Another entry. This will set the ink color at location pointer by DE + and 7 ; # Gets color mod 8 + ld b, a ; Saves the color + ld a, (de) + and 0F8h ; Clears previous value + or b + ld (de), a + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + and 0F8h ; Reset bits 0,1,2 sign to disable transparency + ld (de), a ; Store new attr + ret + + ; Sets the INK color passed in A register in the ATTR_T variable +INK_TMP: + ld de, ATTR_T + jp __SET_INK + + ENDP + +#line 10 "print.asm" +#line 1 "paper.asm" + + ; Sets paper color in ATTR_P permanently +; Parameter: Paper color in A register + + + +PAPER: + PROC + LOCAL __SET_PAPER + LOCAL __SET_PAPER2 + + ld de, ATTR_P + +__SET_PAPER: + cp 8 + jr nz, __SET_PAPER2 + inc de + ld a, (de) + or 038h + ld (de), a + ret + + ; Another entry. This will set the paper color at location pointer by DE +__SET_PAPER2: + and 7 ; # Remove + rlca + rlca + rlca ; a *= 8 + + ld b, a ; Saves the color + ld a, (de) + and 0C7h ; Clears previous value + or b + ld (de), a + inc de ; Points to MASK_T or MASK_P accordingly + ld a, (de) + and 0C7h ; Resets bits 3,4,5 + ld (de), a + ret + + + ; Sets the PAPER color passed in A register in the ATTR_T variable +PAPER_TMP: + ld de, ATTR_T + jp __SET_PAPER + ENDP + +#line 11 "print.asm" +#line 1 "flash.asm" + + ; Sets flash flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +FLASH: + ld de, ATTR_P +__SET_FLASH: + ; Another entry. This will set the flash flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + ld b, a ; Saves the color + ld a, (de) + and 07Fh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the FLASH flag passed in A register in the ATTR_T variable +FLASH_TMP: + ld de, ATTR_T + jr __SET_FLASH + +#line 12 "print.asm" +#line 1 "bright.asm" + + ; Sets bright flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +BRIGHT: + ld de, ATTR_P + +__SET_BRIGHT: + ; Another entry. This will set the bright flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + rrca + ld b, a ; Saves the color + ld a, (de) + and 0BFh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable +BRIGHT_TMP: + ld de, ATTR_T + jr __SET_BRIGHT + +#line 13 "print.asm" +#line 1 "over.asm" + + ; Sets OVER flag in P_FLAG permanently +; Parameter: OVER flag in bit 0 of A register +#line 1 "copy_attr.asm" + + + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" + + + +COPY_ATTR: + ; Just copies current permanent attribs to temporal attribs + ; and sets print mode + PROC + + LOCAL INVERSE1 + LOCAL __REFRESH_TMP + + INVERSE1 EQU 02Fh + + ld hl, (ATTR_P) + ld (ATTR_T), hl + + ld hl, FLAGS2 + call __REFRESH_TMP + + ld hl, P_FLAG + call __REFRESH_TMP + + +__SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) + + + LOCAL TABLE + LOCAL CONT2 + + rra ; Over bit to carry + ld a, (FLAGS2) + rla ; Over bit in bit 1, Over2 bit in bit 2 + and 3 ; Only bit 0 and 1 (OVER flag) + + ld c, a + ld b, 0 + + ld hl, TABLE + add hl, bc + ld a, (hl) + ld (PRINT_MODE), a + + ld hl, (P_FLAG) + xor a ; NOP -> INVERSE0 + bit 2, l + jr z, CONT2 + ld a, INVERSE1 ; CPL -> INVERSE1 + +CONT2: + ld (INVERSE_MODE), a + ret + +TABLE: + nop ; NORMAL MODE + xor (hl) ; OVER 1 MODE + and (hl) ; OVER 2 MODE + or (hl) ; OVER 3 MODE + +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" + +__REFRESH_TMP: + ld a, (hl) + and 10101010b + ld c, a + rra + or c + ld (hl), a + ret + + ENDP + +#line 4 "over.asm" + + +OVER: + PROC + + ld c, a ; saves it for later + and 2 + ld hl, FLAGS2 + res 1, (HL) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 ; # Convert to 0/1 + add a, a; # Shift left 1 bit for permanent + + ld hl, P_FLAG + res 1, (hl) + or (hl) + ld (hl), a + ret + + ; Sets OVER flag in P_FLAG temporarily +OVER_TMP: + ld c, a ; saves it for later + and 2 ; gets bit 1; clears carry + rra + ld hl, FLAGS2 + res 0, (hl) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 + ld hl, P_FLAG + res 0, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 14 "print.asm" +#line 1 "inverse.asm" + + ; Sets INVERSE flag in P_FLAG permanently +; Parameter: INVERSE flag in bit 0 of A register + + + +INVERSE: + PROC + + and 1 ; # Convert to 0/1 + add a, a; # Shift left 3 bits for permanent + add a, a + add a, a + ld hl, P_FLAG + res 3, (hl) + or (hl) + ld (hl), a + ret + + ; Sets INVERSE flag in P_FLAG temporarily +INVERSE_TMP: + and 1 + add a, a + add a, a; # Shift left 2 bits for temporary + ld hl, P_FLAG + res 2, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 15 "print.asm" +#line 1 "bold.asm" + + ; Sets BOLD flag in P_FLAG permanently +; Parameter: BOLD flag in bit 0 of A register + + +BOLD: + PROC + + and 1 + rlca + rlca + rlca + ld hl, FLAGS2 + res 3, (HL) + or (hl) + ld (hl), a + ret + + ; Sets BOLD flag in P_FLAG temporarily +BOLD_TMP: + and 1 + rlca + rlca + ld hl, FLAGS2 + res 2, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 16 "print.asm" +#line 1 "italic.asm" + + ; Sets ITALIC flag in P_FLAG permanently +; Parameter: ITALIC flag in bit 0 of A register + + +ITALIC: + PROC + + and 1 + rrca + rrca + rrca + ld hl, FLAGS2 + res 5, (HL) + or (hl) + ld (hl), a + ret + + ; Sets ITALIC flag in P_FLAG temporarily +ITALIC_TMP: + and 1 + rrca + rrca + rrca + rrca + ld hl, FLAGS2 + res 4, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 17 "print.asm" + +#line 1 "attr.asm" + + ; Attribute routines +; vim:ts=4:et:sw: + + + + + + + +__ATTR_ADDR: + ; calc start address in DE (as (32 * d) + e) + ; Contributed by Santiago Romero at http://www.speccy.org + ld h, 0 ; 7 T-States + ld a, d ; 4 T-States + add a, a ; a * 2 ; 4 T-States + add a, a ; a * 4 ; 4 T-States + ld l, a ; HL = A * 4 ; 4 T-States + + add hl, hl ; HL = A * 8 ; 15 T-States + add hl, hl ; HL = A * 16 ; 15 T-States + add hl, hl ; HL = A * 32 ; 15 T-States + + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) + add hl, de + + ld de, (SCREEN_ADDR) ; Adds the screen address + add hl, de + + ; Return current screen address in HL + ret + + + ; Sets the attribute at a given screen coordinate (D, E). + ; The attribute is taken from the ATTR_T memory variable + ; Used by PRINT routines +SET_ATTR: + + ; Checks for valid coords + call __IN_SCREEN + ret nc + +__SET_ATTR: + ; Internal __FASTCALL__ Entry used by printing routines + PROC + + call __ATTR_ADDR + ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T + + ld a, d + and (hl) + ld c, a ; C = current screen color, masked + + ld a, d + cpl ; Negate mask + and e ; Mask current attributes + or c ; Mix them + ld (hl), a ; Store result in screen + + ret + + ENDP + + +#line 19 "print.asm" + + ; Putting a comment starting with @INIT
+ ; will make the compiler to add a CALL to
+ ; It is useful for initialization routines. + + +__PRINT_INIT: ; To be called before program starts (initializes library) + PROC + + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + + ld hl, 1821h + ld (MAXX), hl ; Sets current maxX and maxY + + xor a + ld (FLAGS2), a + + ret + + +__PRINTCHAR: ; Print character store in accumulator (A register) + ; Modifies H'L', B'C', A'F', D'E', A + + LOCAL PO_GR_1 + + LOCAL __PRCHAR + LOCAL __PRINT_CONT + LOCAL __PRINT_CONT2 + LOCAL __PRINT_JUMP + LOCAL __SRCADDR + LOCAL __PRINT_UDG + LOCAL __PRGRAPH + LOCAL __PRINT_START + + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 + +__PRINT_JUMP: + jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively + +__PRINT_START: + cp ' ' + jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones + + exx ; Switch to alternative registers + ex af, af' ; Saves a value (char to print) for later + + call __LOAD_S_POSN + + ; At this point we have the new coord + ld hl, (SCREEN_ADDR) + + ld a, d + ld c, a ; Saves it for later + + and 0F8h ; Masks 3 lower bit ; zy + ld d, a + + ld a, c ; Recovers it + and 07h ; MOD 7 ; y1 + rrca + rrca + rrca + + or e + ld e, a + add hl, de ; HL = Screen address + DE + ex de, hl ; DE = Screen address + + ex af, af' + + cp 80h ; Is it an UDG or a ? + jp c, __SRCADDR + + cp 90h + jp nc, __PRINT_UDG + + ; Print a 8 bit pattern (80h to 8Fh) + + ld b, a + call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 + ld hl, MEM0 + jp __PRGRAPH + + PO_GR_1 EQU 0B38h + +__PRINT_UDG: + sub 90h ; Sub ASC code + ld bc, (UDG) + jp __PRGRAPH0 + + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source +__SRCADDR: + ld bc, (CHARS) + +__PRGRAPH0: + add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org + ld l, a + ld h, 0 ; HL = a * 2 (accumulator) + add hl, hl + add hl, hl ; HL = a * 8 + add hl, bc ; HL = CHARS address + +__PRGRAPH: + ex de, hl ; HL = Write Address, DE = CHARS address + bit 2, (iy + $47) + call nz, __BOLD + bit 4, (iy + $47) + call nz, __ITALIC + ld b, 8 ; 8 bytes per char +__PRCHAR: + ld a, (de) ; DE *must* be ALWAYS source, and HL destiny + +PRINT_MODE: ; Which operation is used to write on the screen + ; Set it with: + ; LD A, + ; LD (PRINT_MODE), A + ; + ; Available opertions: + ; NORMAL: 0h --> NOP ; OVER 0 + ; XOR : AEh --> XOR (HL) ; OVER 1 + ; OR : B6h --> OR (HL) ; PUTSPRITE + ; AND : A6h --> AND (HL) ; PUTMASK + nop ; + +INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 + nop ; 2F -> CPL -> INVERSE 1 + + ld (hl), a + + inc de + inc h ; Next line + djnz __PRCHAR + + call __LOAD_S_POSN + push de + call __SET_ATTR + pop de + inc e ; COL = COL + 1 + ld hl, (MAXX) + ld a, e + dec l ; l = MAXX + cp l ; Lower than max? + jp c, __PRINT_CONT; Nothing to do + call __PRINT_EOL1 + exx ; counteracts __PRINT_EOL1 exx + jp __PRINT_CONT2 + +__PRINT_CONT: + call __SAVE_S_POSN + +__PRINT_CONT2: + exx + ret + + ; ------------- SPECIAL CHARS (< 32) ----------------- + +__PRINT_SPECIAL: ; Jumps here if it is a special char + exx + ld hl, __PRINT_TABLE + jp JUMP_HL_PLUS_2A + + +PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence + exx + +__PRINT_0Dh: ; Called WHEN printing CHR$(13) + call __LOAD_S_POSN + +__PRINT_EOL1: ; Another entry called from PRINT when next line required + ld e, 0 + +__PRINT_EOL2: + ld a, d + inc a + +__PRINT_AT1_END: + ld hl, (MAXY) + cp l + jr c, __PRINT_EOL_END ; Carry if (MAXY) < d + xor a + +__PRINT_EOL_END: + ld d, a + +__PRINT_AT2_END: + call __SAVE_S_POSN + exx + ret + +__PRINT_COM: + exx + push hl + push de + push bc + call PRINT_COMMA + pop bc + pop de + pop hl + ret + +__PRINT_TAB: + ld hl, __PRINT_TAB1 + jp __PRINT_SET_STATE + +__PRINT_TAB1: + ld (MEM0), a + ld hl, __PRINT_TAB2 + ld (PRINT_JUMP_STATE), hl + ret + +__PRINT_TAB2: + ld a, (MEM0) ; Load tab code (ignore the current one) + push hl + push de + push bc + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + call PRINT_TAB + pop bc + pop de + pop hl + ret + +__PRINT_NOP: +__PRINT_RESTART: + ld hl, __PRINT_START + jp __PRINT_SET_STATE + +__PRINT_AT: + ld hl, __PRINT_AT1 + +__PRINT_SET_STATE: + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + exx + ret + +__PRINT_AT1: ; Jumps here if waiting for 1st parameter + exx + ld hl, __PRINT_AT2 + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + jp __PRINT_AT1_END + +__PRINT_AT2: + exx + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + ld e, a + ld hl, (MAXX) + cp (hl) + jr c, __PRINT_AT2_END + jr __PRINT_EOL1 + +__PRINT_DEL: + call __LOAD_S_POSN ; Gets current screen position + dec e + ld a, -1 + cp e + jp nz, __PRINT_AT2_END + ld hl, (MAXX) + ld e, l + dec e + dec e + dec d + cp d + jp nz, __PRINT_AT2_END + ld d, h + dec d + jp __PRINT_AT2_END + +__PRINT_INK: + ld hl, __PRINT_INK2 + jp __PRINT_SET_STATE + +__PRINT_INK2: + exx + call INK_TMP + jp __PRINT_RESTART + +__PRINT_PAP: + ld hl, __PRINT_PAP2 + jp __PRINT_SET_STATE + +__PRINT_PAP2: + exx + call PAPER_TMP + jp __PRINT_RESTART + +__PRINT_FLA: + ld hl, __PRINT_FLA2 + jp __PRINT_SET_STATE + +__PRINT_FLA2: + exx + call FLASH_TMP + jp __PRINT_RESTART + +__PRINT_BRI: + ld hl, __PRINT_BRI2 + jp __PRINT_SET_STATE + +__PRINT_BRI2: + exx + call BRIGHT_TMP + jp __PRINT_RESTART + +__PRINT_INV: + ld hl, __PRINT_INV2 + jp __PRINT_SET_STATE + +__PRINT_INV2: + exx + call INVERSE_TMP + jp __PRINT_RESTART + +__PRINT_OVR: + ld hl, __PRINT_OVR2 + jp __PRINT_SET_STATE + +__PRINT_OVR2: + exx + call OVER_TMP + jp __PRINT_RESTART + +__PRINT_BOLD: + ld hl, __PRINT_BOLD2 + jp __PRINT_SET_STATE + +__PRINT_BOLD2: + exx + call BOLD_TMP + jp __PRINT_RESTART + +__PRINT_ITA: + ld hl, __PRINT_ITA2 + jp __PRINT_SET_STATE + +__PRINT_ITA2: + exx + call ITALIC_TMP + jp __PRINT_RESTART + + +__BOLD: + push hl + ld hl, MEM0 + ld b, 8 +__BOLD_LOOP: + ld a, (de) + ld c, a + rlca + or c + ld (hl), a + inc hl + inc de + djnz __BOLD_LOOP + pop hl + ld de, MEM0 + ret + + +__ITALIC: + push hl + ld hl, MEM0 + ex de, hl + ld bc, 8 + ldir + ld hl, MEM0 + srl (hl) + inc hl + srl (hl) + inc hl + srl (hl) + inc hl + inc hl + inc hl + sla (hl) + inc hl + sla (hl) + inc hl + sla (hl) + pop hl + ld de, MEM0 + ret + +PRINT_COMMA: + call __LOAD_S_POSN + ld a, e + and 16 + add a, 16 + +PRINT_TAB: + PROC + LOCAL LOOP, CONTINUE + + inc a + call __LOAD_S_POSN ; e = current row + ld d, a + ld a, e + cp 21h + jr nz, CONTINUE + ld e, -1 +CONTINUE: + ld a, d + inc e + sub e ; A = A - E + and 31 ; + ret z ; Already at position E + ld b, a +LOOP: + ld a, ' ' + call __PRINTCHAR + djnz LOOP + ret + ENDP + +PRINT_AT: ; CHanges cursor to ROW, COL + ; COL in A register + ; ROW in stack + + pop hl ; Ret address + ex (sp), hl ; callee H = ROW + ld l, a + ex de, hl + + call __IN_SCREEN + ret nc ; Return if out of screen + + jp __SAVE_S_POSN + + LOCAL __PRINT_COM + LOCAL __BOLD + LOCAL __BOLD_LOOP + LOCAL __ITALIC + LOCAL __PRINT_EOL1 + LOCAL __PRINT_EOL2 + LOCAL __PRINT_AT1 + LOCAL __PRINT_AT2 + LOCAL __PRINT_AT2_END + LOCAL __PRINT_BOLD + LOCAL __PRINT_BOLD2 + LOCAL __PRINT_ITA + LOCAL __PRINT_ITA2 + LOCAL __PRINT_INK + LOCAL __PRINT_PAP + LOCAL __PRINT_SET_STATE + LOCAL __PRINT_TABLE + LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 + +__PRINT_TABLE: ; Jump table for 0 .. 22 codes + + DW __PRINT_NOP ; 0 + DW __PRINT_NOP ; 1 + DW __PRINT_NOP ; 2 + DW __PRINT_NOP ; 3 + DW __PRINT_NOP ; 4 + DW __PRINT_NOP ; 5 + DW __PRINT_COM ; 6 COMMA + DW __PRINT_NOP ; 7 + DW __PRINT_DEL ; 8 DEL + DW __PRINT_NOP ; 9 + DW __PRINT_NOP ; 10 + DW __PRINT_NOP ; 11 + DW __PRINT_NOP ; 12 + DW __PRINT_0Dh ; 13 + DW __PRINT_BOLD ; 14 + DW __PRINT_ITA ; 15 + DW __PRINT_INK ; 16 + DW __PRINT_PAP ; 17 + DW __PRINT_FLA ; 18 + DW __PRINT_BRI ; 19 + DW __PRINT_INV ; 20 + DW __PRINT_OVR ; 21 + DW __PRINT_AT ; 22 AT + DW __PRINT_TAB ; 23 TAB + + ENDP + + +#line 93 "readokdown.bas" +#line 1 "printf.asm" + +#line 1 "printstr.asm" + + + + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 5 "printstr.asm" + + ; PRINT command routine + ; Prints string pointed by HL + +PRINT_STR: +__PRINTSTR: ; __FASTCALL__ Entry to print_string + PROC + LOCAL __PRINT_STR_LOOP + LOCAL __PRINT_STR_END + + ld d, a ; Saves A reg (Flag) for later + + ld a, h + or l + ret z ; Return if the pointer is NULL + + push hl + + ld c, (hl) + inc hl + ld b, (hl) + inc hl ; BC = LEN(a$); HL = &a$ + +__PRINT_STR_LOOP: + ld a, b + or c + jr z, __PRINT_STR_END ; END if BC (counter = 0) + + ld a, (hl) + call __PRINTCHAR + inc hl + dec bc + jp __PRINT_STR_LOOP + +__PRINT_STR_END: + pop hl + ld a, d ; Recovers A flag + or a ; If not 0 this is a temporary string. Free it + ret z + jp __MEM_FREE ; Frees str from heap and return from there + +__PRINT_STR: + ; Fastcall Entry + ; It ONLY prints strings + ; HL = String start + ; BC = String length (Number of chars) + push hl ; Push str address for later + ld d, a ; Saves a FLAG + jp __PRINT_STR_LOOP + + ENDP + +#line 2 "printf.asm" +#line 1 "stackf.asm" + + ; ------------------------------------------------------------- + ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC + ; ------------------------------------------------------------- + + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) + __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) + +__FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) + ; Second argument to push into the stack calculator is popped out of the stack + ; Since the caller routine also receives the parameters into the top of the stack + ; four bytes must be removed from SP before pop them out + + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK + exx + pop hl ; Caller-Caller return addr + exx + pop hl ; Caller return addr + + pop af + pop de + pop bc + + push hl ; Caller return addr + exx + push hl ; Caller-Caller return addr + exx + + jp __FPSTACK_PUSH + + +__FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK + ; This format is specified in the ZX 48K Manual + ; You can push a 16 bit signed integer as + ; 0 SS LL HH 0, being SS the sign and LL HH the low + ; and High byte respectively + ld a, h + rla ; sign to Carry + sbc a, a ; 0 if positive, FF if negative + ld e, a + ld d, l + ld c, h + xor a + ld b, a + jp __FPSTACK_PUSH +#line 3 "printf.asm" + + +__PRINTF: ; Prints a Fixed point Number stored in C ED LH + PROC + + LOCAL RECLAIM2 + LOCAL STK_END + STK_END EQU 5C65h + + ld hl, (ATTR_T) + push hl ; Saves ATTR_T since BUG ROM changes it + + ld hl, (STK_END) + push hl ; Stores STK_END + + call __FPSTACK_PUSH ; Push number into stack + rst 28h ; # Rom Calculator + defb 2Eh ; # STR$(x) + defb 38h ; # END CALC + call __FPSTACK_POP ; Recovers string parameters to A ED CB + + pop hl + ld (STK_END), hl ; Balance STK_END to avoid STR$ bug + + pop hl + ld (ATTR_T), hl ; Restores ATTR_T + + ex de, hl ; String position now in HL + + push bc + xor a ; Avoid the str to be FREED from heap + call __PRINT_STR + pop bc + inc bc + + jp RECLAIM2 ; Frees TMP Memory + + RECLAIM2 EQU 19E8h + + ENDP + +#line 94 "readokdown.bas" +#line 1 "printf16.asm" + +#line 1 "printnum.asm" + + + + +__PRINTU_START: + PROC + + LOCAL __PRINTU_CONT + + ld a, b + or a + jp nz, __PRINTU_CONT + + ld a, '0' + jp __PRINT_DIGIT + + +__PRINTU_CONT: + pop af + push bc + call __PRINT_DIGIT + pop bc + djnz __PRINTU_CONT + ret + + ENDP + + +__PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers + ld a, '-' + jp __PRINT_DIGIT + + __PRINT_DIGIT EQU __PRINTCHAR ; PRINTS the char in A register, and puts its attrs + + +#line 2 "printf16.asm" +#line 1 "printi16.asm" + + +#line 1 "div16.asm" + + ; 16 bit division and modulo functions + ; for both signed and unsigned values + +#line 1 "neg16.asm" + + ; Negates HL value (16 bit) +__ABS16: + bit 7, h + ret z + +__NEGHL: + ld a, l ; HL = -HL + cpl + ld l, a + ld a, h + cpl + ld h, a + inc hl + ret + +#line 5 "div16.asm" + +__DIVU16: ; 16 bit unsigned division + ; HL = Dividend, Stack Top = Divisor + + ; -- OBSOLETE ; Now uses FASTCALL convention + ; ex de, hl + ; pop hl ; Return address + ; ex (sp), hl ; CALLEE Convention + +__DIVU16_FAST: + ld a, h + ld c, l + ld hl, 0 + ld b, 16 + +__DIV16LOOP: + sll c + rla + adc hl,hl + sbc hl,de + jr nc, __DIV16NOADD + add hl,de + dec c + +__DIV16NOADD: + djnz __DIV16LOOP + + ex de, hl + ld h, a + ld l, c + + ret ; HL = quotient, DE = Mudulus + + + +__MODU16: ; 16 bit modulus + ; HL = Dividend, Stack Top = Divisor + + ;ex de, hl + ;pop hl + ;ex (sp), hl ; CALLEE Convention + + call __DIVU16_FAST + ex de, hl ; hl = reminder (modulus) + ; de = quotient + + ret + + +__DIVI16: ; 16 bit signed division + ; --- The following is OBSOLETE --- + ; ex de, hl + ; pop hl + ; ex (sp), hl ; CALLEE Convention + +__DIVI16_FAST: + ld a, d + xor h + ex af, af' ; BIT 7 of a contains result + + bit 7, d ; DE is negative? + jr z, __DIVI16A + + ld a, e ; DE = -DE + cpl + ld e, a + ld a, d + cpl + ld d, a + inc de + +__DIVI16A: + bit 7, h ; HL is negative? + call nz, __NEGHL + +__DIVI16B: + call __DIVU16_FAST + ex af, af' + + or a + ret p ; return if positive + jp __NEGHL + + +__MODI16: ; 16 bit modulus + ; HL = Dividend, Stack Top = Divisor + + ;ex de, hl + ;pop hl + ;ex (sp), hl ; CALLEE Convention + + call __DIVI16_FAST + ex de, hl ; hl = reminder (modulus) + ; de = quotient + + ret + +#line 3 "printi16.asm" + + + +__PRINTI16: ; Prints a 16bits signed in HL + ; Converts 16 to 32 bits + PROC + + LOCAL __PRINTU_LOOP + ld a, h + or a + + jp p, __PRINTU16 + + call __PRINT_MINUS + call __NEGHL + +__PRINTU16: + + ld b, 0 +__PRINTU_LOOP: + ld a, h + or l + jp z, __PRINTU_START + + push bc + ld de, 10 + call __DIVU16_FAST ; Divides by DE. DE = MODULUS at exit. Since < 256, E = Modulus + pop bc + + ld a, e + or '0' ; Stores ASCII digit (must be print in reversed order) + push af + inc b + jp __PRINTU_LOOP ; Uses JP in loops + + ENDP + +#line 3 "printf16.asm" +#line 1 "neg32.asm" + +__ABS32: + bit 7, d + ret z + +__NEG32: ; Negates DEHL (Two's complement) + ld a, l + cpl + ld l, a + + ld a, h + cpl + ld h, a + + ld a, e + cpl + ld e, a + + ld a, d + cpl + ld d, a + + inc l + ret nz + + inc h + ret nz + + inc de + ret + +#line 4 "printf16.asm" + +__PRINTF16: ; Prints a 32bit 16.16 fixed point number + PROC + + LOCAL __PRINT_FIX_LOOP + LOCAL __PRINTF16_2 + + bit 7, d + jr z, __PRINTF16_2 + call __NEG32 + call __PRINT_MINUS + +__PRINTF16_2: + push hl + ex de, hl + call __PRINTU16 ; Prints integer part + pop hl + + ld a, h + or l + ret z ; Returns if integer + + push hl + ld a, '.' + call __PRINT_DIGIT ; Prints decimal point + pop hl + +__PRINT_FIX_LOOP: + ld a, h + or l + ret z ; Returns if no more decimals + + xor a + ld d, h + ld e, l + ; Fast NUM * 10 multiplication + add hl, hl ; + adc a, a ; AHL = AHL * 2 (= X * 2) + add hl, hl ; + adc a, a ; AHL = AHL * 2 (= X * 4) + + add hl, de ; + adc a, 0 ; AHL = AHL + DE (= X * 5) + add hl, hl + adc a, a ; AHL = AHL * 2 (= X * 10) + + push hl + or '0' + call __PRINT_DIGIT + pop hl + jp __PRINT_FIX_LOOP + + ENDP + +#line 95 "readokdown.bas" + +#line 1 "printi32.asm" + + + +#line 1 "div32.asm" + + + + ; --------------------------------------------------------- +__DIVU32: ; 32 bit unsigned division + ; DEHL = Dividend, Stack Top = Divisor + ; OPERANDS P = Dividend, Q = Divisor => OPERATION => P / Q + ; + ; Changes A, BC DE HL B'C' D'E' H'L' + ; --------------------------------------------------------- + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + +__DIVU32START: ; Performs D'E'H'L' / HLDE + ; Now switch to DIVIDEND = B'C'BC / DIVISOR = D'E'DE (A / B) + push de ; push Lowpart(Q) + ex de, hl ; DE = HL + ld hl, 0 + exx + ld b, h + ld c, l + pop hl + push de + ex de, hl + ld hl, 0 ; H'L'HL = 0 + exx + pop bc ; Pop HightPart(B) => B = B'C'BC + exx + + ld a, 32 ; Loop count + +__DIV32LOOP: + sll c ; B'C'BC << 1 ; Output most left bit to carry + rl b + exx + rl c + rl b + exx + + adc hl, hl + exx + adc hl, hl + exx + + sbc hl,de + exx + sbc hl,de + exx + jp nc, __DIV32NOADD ; use JP inside a loop for being faster + + add hl, de + exx + adc hl, de + exx + dec bc + +__DIV32NOADD: + dec a + jp nz, __DIV32LOOP ; use JP inside a loop for being faster + ; At this point, quotient is stored in B'C'BC and the reminder in H'L'HL + + push hl + exx + pop de + ex de, hl ; D'E'H'L' = 32 bits modulus + push bc + exx + pop de ; DE = B'C' + ld h, b + ld l, c ; DEHL = quotient D'E'H'L' = Modulus + + ret ; DEHL = quotient, D'E'H'L' = Modulus + + + +__MODU32: ; 32 bit modulus for 32bit unsigned division + ; DEHL = Dividend, Stack Top = Divisor (DE, HL) + + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + + call __DIVU32START ; At return, modulus is at D'E'H'L' + +__MODU32START: + + exx + push de + push hl + + exx + pop hl + pop de + + ret + + +__DIVI32: ; 32 bit signed division + ; DEHL = Dividend, Stack Top = Divisor + ; A = Dividend, B = Divisor => A / B + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + +__DIVI32START: + exx + ld a, d ; Save sign + ex af, af' + bit 7, d ; Negative? + call nz, __NEG32 ; Negates DEHL + + exx ; Now works with H'L'D'E' + ex af, af' + xor h + ex af, af' ; Stores sign of the result for later + + bit 7, h ; Negative? + ex de, hl ; HLDE = DEHL + call nz, __NEG32 + ex de, hl + + call __DIVU32START + ex af, af' ; Recovers sign + and 128 ; positive? + ret z + + jp __NEG32 ; Negates DEHL and returns from there + + +__MODI32: ; 32bits signed division modulus + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + + call __DIVI32START + jp __MODU32START + +#line 4 "printi32.asm" + + + +__PRINTI32: + ld a, d + or a + jp p, __PRINTU32 + + call __PRINT_MINUS + call __NEG32 + +__PRINTU32: + PROC + LOCAL __PRINTU_LOOP + + ld b, 0 ; Counter + +__PRINTU_LOOP: + ld a, h + or l + or d + or e + jp z, __PRINTU_START + + push bc + + ld bc, 0 + push bc + ld bc, 10 + push bc ; Push 00 0A (10 Dec) into the stack = divisor + + call __DIVU32 ; Divides by 32. D'E'H'L' contains modulo (L' since < 10) + pop bc + + exx + ld a, l + or '0' ; Stores ASCII digit (must be print in reversed order) + push af + exx + inc b + jp __PRINTU_LOOP ; Uses JP in loops + + ENDP + +#line 97 "readokdown.bas" +#line 1 "printi8.asm" + + +#line 1 "div8.asm" + + ; -------------------------------- +__DIVU8: ; 8 bit unsigned integer division + ; Divides (Top of stack, High Byte) / A + pop hl ; -------------------------------- + ex (sp), hl ; CALLEE + +__DIVU8_FAST: ; Does A / H + ld l, h + ld h, a ; At this point do H / L + + ld b, 8 + xor a ; A = 0, Carry Flag = 0 + +__DIV8LOOP: + sla h + rla + cp l + jr c, __DIV8NOSUB + sub l + inc h + +__DIV8NOSUB: + djnz __DIV8LOOP + + ld l, a ; save remainder + ld a, h ; + + ret ; a = Quotient, + + + ; -------------------------------- +__DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A + pop hl ; -------------------------------- + ex (sp), hl + +__DIVI8_FAST: + ld e, a ; store operands for later + ld c, h + + or a ; negative? + jp p, __DIV8A + neg ; Make it positive + +__DIV8A: + ex af, af' + ld a, h + or a + jp p, __DIV8B + neg + ld h, a ; make it positive + +__DIV8B: + ex af, af' + + call __DIVU8_FAST + + ld a, c + xor l ; bit 7 of A = 1 if result is negative + + ld a, h ; Quotient + ret p ; return if positive + + neg + ret + + +__MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) + pop hl + ex (sp), hl ; CALLEE + +__MODU8_FAST: ; __FASTCALL__ entry + call __DIVU8_FAST + ld a, l ; Remainder + + ret ; a = Modulus + + +__MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) + pop hl + ex (sp), hl ; CALLEE + +__MODI8_FAST: ; __FASTCALL__ entry + call __DIVI8_FAST + ld a, l ; remainder + + ret ; a = Modulus + +#line 3 "printi8.asm" + +__PRINTI8: ; Prints an 8 bits number in Accumulator (A) + ; Converts 8 to 32 bits + or a + jp p, __PRINTU8 + + push af + call __PRINT_MINUS + pop af + neg + +__PRINTU8: + PROC + + LOCAL __PRINTU_LOOP + + ld b, 0 ; Counter + +__PRINTU_LOOP: + or a + jp z, __PRINTU_START + + push bc + ld h, 10 + call __DIVU8_FAST ; Divides by 10. D'E'H'L' contains modulo (L' since < 10) + pop bc + + ld a, l + or '0' ; Stores ASCII digit (must be print in reversed order) + push af + ld a, h + inc b + jp __PRINTU_LOOP ; Uses JP in loops + + ENDP + +#line 98 "readokdown.bas" +#line 1 "printu16.asm" + + + +#line 99 "readokdown.bas" +#line 1 "printu32.asm" + + + +#line 100 "readokdown.bas" +#line 1 "printu8.asm" + + + +#line 101 "readokdown.bas" +#line 1 "read_restore.asm" + + ;; This implements READ & RESTORE functions + ;; Reads a new element from the DATA Address code + ;; Updates the DATA_ADDR read ptr for the next read + + ;; Data codification is 1 byte for type followed by data bytes + ;; Byte type is encoded as follows + +;; 00: End of data +;; 01: String +;; 02: Byte +;; 03: Ubyte +;; 04: Integer +;; 05: UInteger +;; 06: Long +;; 07: ULong +;; 08: Fixed +;; 09: Float + + ;; bit7 is set for a parameter-less function + ;; In that case, the next two bytes are the ptr of the function to jump + + +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 24 "read_restore.asm" +#line 1 "iload32.asm" + + ; __FASTCALL__ routine which + ; loads a 32 bits integer into DE,HL + ; stored at position pointed by POINTER HL + ; DE,HL <-- (HL) + +__ILOAD32: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + ex de, hl + ret + +#line 25 "read_restore.asm" +#line 1 "iloadf.asm" + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- ((HL)) + +__ILOADF: + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- (HL) + +__LOADF: ; Loads a 40 bits FP number from address pointed by HL + ld a, (hl) + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld c, (hl) + inc hl + ld b, (hl) + ret + +#line 26 "read_restore.asm" +#line 1 "ftof16reg.asm" + +#line 1 "ftou32reg.asm" + + + +__FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + ; Output: DEHL 32 bit number (signed) + PROC + + LOCAL __IS_FLOAT + + or a + jr nz, __IS_FLOAT + ; Here if it is a ZX ROM Integer + + ld h, c + ld l, d + ld a, e ; Takes sign: FF = -, 0 = + + ld de, 0 + inc a + jp z, __NEG32 ; Negates if negative + ret + +__IS_FLOAT: ; Jumps here if it is a true floating point number + ld h, e + push hl ; Stores it for later (Contains Sign in H) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + ;ld a, c ; Get exponent + sub 128 ; Exponent -= 128 + jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + +__FTOU32REG_LOOP: + exx ; Shift C'B' E'D' << 1, output bit stays in Carry + sla d + rl e + rl b + rl c + + exx ; Shift DEHL << 1, inserting the carry on the right + rl l + rl h + rl e + rl d + + djnz __FTOU32REG_LOOP + +__FTOU32REG_END: + pop af ; Take the sign bit + or a ; Sets SGN bit to 1 if negative + jp m, __NEG32 ; Negates DEHL + + ret + + ENDP + + +__FTOU8: ; Converts float in C ED LH to Unsigned byte in A + call __FTOU32REG + ld a, l + ret + +#line 2 "ftof16reg.asm" + +__FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + + ld l, a ; Saves exponent for later + or d + or e + or b + or c + ld h, e + ret z ; Return if ZERO + + push hl ; Stores it for later (Contains sign in H, exponent in L) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + pop bc + + ld a, c ; Get exponent + sub 112 ; Exponent -= 128 + 16 + + push bc ; Saves sign in b again + + jp z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jp c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + 16 (we need to shift 16 bit more) + jp __FTOU32REG_LOOP ; proceed as an u32 integer + +#line 27 "read_restore.asm" +#line 1 "f16tofreg.asm" + + +#line 1 "u32tofreg.asm" + + +__I8TOFREG: + ld l, a + rlca + sbc a, a ; A = SGN(A) + ld h, a + ld e, a + ld d, a + +__I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) + ; to a Floating Point Number returned in (A ED CB) + + ld a, d + or a ; Test sign + + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __U32TOFREG ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + +__U8TOFREG: + ; Converts an unsigned 8 bit (A) to Floating point + ld l, a + ld h, 0 + ld e, h + ld d, h + +__U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in A ED CB + + PROC + + LOCAL __U32TOFREG_END + + ld a, d + or e + or h + or l + ld b, d + ld c, e ; Returns 00 0000 0000 if ZERO + ret z + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 128 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + +__U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG + exx + ld a, d ; B'C'D'E' == 0 ? + or e + or b + or c + jp z, __U32TOFREG_END ; We are done + + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry + rr c + rr d + rr e + exx + + rr e ; Shift EDCB >> 1, inserting the carry on the left + rr d + rr c + rr b + + inc l ; Increment exponent + jp __U32TOFREG_LOOP + + +__U32TOFREG_END: + exx + ld a, l ; Puts the exponent in a + res 7, e ; Sets the sign bit to 0 (positive) + + ret + ENDP + +#line 3 "f16tofreg.asm" + +__F16TOFREG: ; Converts a 16.16 signed fixed point (stored in DEHL) + ; to a Floating Point Number returned in (C ED CB) + PROC + + LOCAL __F16TOFREG2 + + ld a, d + or a ; Test sign + + jp p, __F16TOFREG2 ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __F16TOFREG2 ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + + +__F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in C DE HL + + ld a, d + or e + or h + or l + ld b, h + ld c, l + ret z ; Return 00 0000 0000 if 0 + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 112 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + jp __U32TOFREG_LOOP ; Proceed as an integer + + ENDP + +#line 28 "read_restore.asm" + + + + + + + + + + + + + + ;; Updates restore point to the given HL mem. address +__RESTORE: + PROC + LOCAL __DATA_ADDR + + ld (__DATA_ADDR), hl + ret + + ;; Reads a value from the DATA mem area and updates __DATA_ADDR ptr to the + ;; next item. On Out Of Data, restarts + ;; +__READ: + LOCAL read_restart, cont, cont2, table, no_func + LOCAL dynamic_cast, dynamic_cast2, dynamic_cast3, dynamic_cast4 + LOCAL _decode_table, coerce_to_int, coerce_to_int2, promote_to_i16 + LOCAL _from_i8, _from_u8 + LOCAL _from_i16, _from_u16 + LOCAL _from_i32, _from_u32 + LOCAL _from_fixed, __data_error + + push af ; type of data to read + ld hl, (__DATA_ADDR) +read_restart: + ld a, (hl) + or a ; 0 => OUT of data + jr nz, cont + ;; Signals out of data + + ld hl, __DATA__0 + ld (__DATA_ADDR), hl + jr read_restart ; Start again +cont: + and 0x80 + ld a, (hl) + push af + jp z, no_func ;; Loads data directly, not a function + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl +cont2: + ld de, dynamic_cast + push de ; ret address + jp (hl) ; "call (hl)" + + ;; Now tries to convert the given result to the expected type or raise an error +dynamic_cast: + exx + ex af, af' + pop af ; type READ + and 0x7F ; clear bit 7 + pop hl ; type requested by USER (type of the READ variable) + ld c, h ; save requested type (save it in register C) + cp h + exx + jr nz, dynamic_cast2 ; Types are identical? + ;; yes, they are + ex af, af' + ret + +dynamic_cast2: + cp 1 ; Requested a number, but read a string? + jr nz, dynamic_cast3 + call __MEM_FREE ; Frees str from memory + jr __data_error + +dynamic_cast3: + exx + ld b, a ; Read type + ld a, c ; Requested type + cp 1 + jr z, __data_error + cp b + jr c, dynamic_cast4 + ;; here the user expected type is "larger" than the read one + ld a, b + sub 2 + add a, a + ld l, a + ld h, 0 + ld de, _decode_table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl + ld a, c ; Requested type + exx + ret + +__data_error: + ;; When a data is read, but cannot be converted to the requested type + ;; that is, the user asked for a string and we read a number or vice versa + ld a, ERROR_InvalidArg + call __STOP ; The user expected a string, but read a number + xor a + ld h, a + ld l, a + ld e, a + ld d, a + ld b, a + ld c, a + ret + +_decode_table: + dw _from_i8 + dw _from_u8 + dw _from_i16 + dw _from_u16 + dw _from_i32 + dw _from_u32 + dw _from_fixed + +_from_i8: + cp 4 + jr nc, promote_to_i16 + ex af, af' + ret ;; Was from Byte to Ubyte + +promote_to_i16: + ex af, af' + ld l, a + rla + sbc a, a + ld h, a ; copy sgn to h + ex af, af' + jr _before_from_i16 + +_from_u8: + ex af, af' + ld l, a + ld h, 0 + ex af, af' + ;; Promoted to i16 + +_before_from_i16: +_from_i16: + cp 6 + ret c ;; from i16 to u16 + ;; Promote i16 to i32 + ex af, af' + ld a, h + rla + sbc a, a + ld e, a + ld d, a + ex af, af' +_from_i32: + cp 7 + ret z ;; From i32 to u32 + ret c ;; From u16 to i32 + cp 9 + jp z, __I32TOFREG +_from_u32: + cp 9 + jp z, __U32TOFREG + ex de, hl + ld hl, 0 + cp 8 + ret z +_from_fixed: ;; From fixed to float + jp __F16TOFREG +_from_u16: + ld de, 0 ; HL 0x0000 => 32 bits + jp _from_i32 + +dynamic_cast4: + ;; The user type is "shorter" than the read one + cp 8 ;; required type + jr c, before_to_int ;; required < fixed (f16) + ex af, af' + exx ;; Ok, we must convert from float to f16 + jp __FTOF16REG + +before_to_int: + ld a, b ;; read type + cp 8 ;; + jr nz, coerce_to_int ;; From float to int + ld a, c ;; user type + exx + ;; f16 to Long + ex de, hl + ld a, h + rla + sbc a, a + ld d, a + ld e, a + exx + jr coerce_to_int2 +coerce_to_int: + exx + ex af, af' + call __FTOU32REG + ex af, af' ; a contains user type + exx +coerce_to_int2: ; At this point we have an u/integer in hl + exx + cp 4 + ret nc ; Already done. Return the result + ld a, l ; Truncate to byte + ret + +no_func: + exx + ld de, dynamic_cast + push de ; Ret address + dec a ; 0 => string; 1, 2 => byte; 3, 4 => integer; 5, 6 => long, 7 => fixed; 8 => float + ld h, 0 + add a, a + ld l, a + ld de, table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl ; address to jump to + exx + inc hl + ret ; jp (sp) => jump to table[a - 1] + +table: + LOCAL __01_decode_string + LOCAL __02_decode_byte + LOCAL __03_decode_ubyte + LOCAL __04_decode_integer + LOCAL __05_decode_uinteger + LOCAL __06_decode_long + LOCAL __07_decode_ulong + LOCAL __08_decode_fixed + LOCAL __09_decode_float + + ;; 1 -> Decode string + ;; 2, 3 -> Decode Byte, UByte + ;; 4, 5 -> Decode Integer, UInteger + ;; 6, 7 -> Decode Long, ULong + ;; 8 -> Decode Fixed + ;; 9 -> Decode Float + dw __01_decode_string + dw __02_decode_byte + dw __03_decode_ubyte + dw __04_decode_integer + dw __05_decode_uinteger + dw __06_decode_long + dw __07_decode_ulong + dw __08_decode_fixed + dw __09_decode_float + +__01_decode_string: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl + jp __LOADSTR + +__02_decode_byte: +__03_decode_ubyte: + ld a, (hl) + inc hl + ld (__DATA_ADDR), hl + ret + +__04_decode_integer: +__05_decode_uinteger: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl + ex de, hl + ret + +__06_decode_long: +__07_decode_ulong: +__08_decode_fixed: + ld b, h + ld c, l + inc bc + inc bc + inc bc + inc bc + ld (__DATA_ADDR), bc + jp __ILOAD32 + +__09_decode_float: + call __LOADF + inc hl + ld (__DATA_ADDR), hl + ld h, a ; returns A in H; sets A free + ret + +__DATA_ADDR: ;; Stores current DATA ptr + dw __DATA__0 + ENDP + + + + + + + + + + +#line 102 "readokdown.bas" +#line 1 "storef.asm" + +__PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) + push de + ex de, hl ; DE <- HL + push ix + pop hl ; HL <- IX + add hl, de ; HL <- IX + HL + pop de + +__ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register + ex af, af' + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex af, af' + +__STOREF: ; Stores the given FP number in A EDCB at address HL + ld (hl), a + inc hl + ld (hl), e + inc hl + ld (hl), d + inc hl + ld (hl), c + inc hl + ld (hl), b + ret + +#line 103 "readokdown.bas" + +ZXBASIC_USER_DATA: +_i8: + DEFB 00 +_u8: + DEFB 00 +_i16: + DEFB 00, 00 +_u16: + DEFB 00, 00 +_i32: + DEFB 00, 00, 00, 00 +_u32: + DEFB 00, 00, 00, 00 +_f16: + DEFB 00, 00, 00, 00 +_flt: + DEFB 00, 00, 00, 00, 00 +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/readokdown.bas b/tests/functional/readokdown.bas new file mode 100644 index 000000000..66f6b15e7 --- /dev/null +++ b/tests/functional/readokdown.bas @@ -0,0 +1,43 @@ +REM Type coerding (reduction) in read DATA + +DIM i8 as Byte +DIM u8 as UByte +DIM i16 as Integer +DIM u16 as UInteger +DIM i32 as Long +DIM u32 as ULong +DIM f16 as Fixed +DIM flt as Float + +RESTORE +READ i8 +PRINT i8 +RESTORE +READ u8 +PRINT u8 + +RESTORE +READ i16 +PRINT i16 +RESTORE +READ u16 +PRINT u16 + +RESTORE +READ i32 +PRINT i32 +RESTORE +READ u32 +PRINT u32 + +RESTORE +READ f16 +PRINT f16 + +RESTORE +READ flt +PRINT flt + +DATA -33000.153423423 + + diff --git a/tests/functional/readokup.asm b/tests/functional/readokup.asm new file mode 100644 index 000000000..5db26259d --- /dev/null +++ b/tests/functional/readokup.asm @@ -0,0 +1,3276 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + call __PRINT_INIT + ld hl, __DATA__0 + call __RESTORE + ld a, 2 + call __READ + ld (_i8), a + call __PRINTI8 + call PRINT_EOL + ld hl, __DATA__0 + call __RESTORE + ld a, 3 + call __READ + ld (_u8), a + call __PRINTU8 + call PRINT_EOL + ld hl, __DATA__0 + call __RESTORE + ld a, 4 + call __READ + ld (_i16), hl + call __PRINTI16 + call PRINT_EOL + ld hl, __DATA__0 + call __RESTORE + ld a, 5 + call __READ + ld (_u16), hl + call __PRINTU16 + call PRINT_EOL + ld hl, __DATA__0 + call __RESTORE + ld a, 6 + call __READ + ld (_i32), hl + ld (_i32 + 2), de + ld hl, (_i32) + ld de, (_i32 + 2) + call __PRINTI32 + call PRINT_EOL + ld hl, __DATA__0 + call __RESTORE + ld a, 7 + call __READ + ld (_u32), hl + ld (_u32 + 2), de + ld hl, (_u32) + ld de, (_u32 + 2) + call __PRINTU32 + call PRINT_EOL + ld hl, __DATA__0 + call __RESTORE + ld a, 8 + call __READ + ld (_f16), hl + ld (_f16 + 2), de + ld hl, (_f16) + ld de, (_f16 + 2) + call __PRINTF16 + call PRINT_EOL + ld hl, __DATA__0 + call __RESTORE + ld a, 9 + call __READ + ld hl, _flt + call __STOREF + ld a, (_flt) + ld de, (_flt + 1) + ld bc, (_flt + 3) + call __PRINTF + call PRINT_EOL + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__DATA__0: + DEFB 2 + DEFB -1 +__DATA__END: + DEFB 00h +#line 1 "print.asm" + +; vim:ts=4:sw=4:et: + ; PRINT command routine + ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that + +#line 1 "sposn.asm" + + ; Printing positioning library. + PROC + LOCAL ECHO_E + +__LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. + ld de, (S_POSN) + ld hl, (MAXX) + or a + sbc hl, de + ex de, hl + ret + + +__SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. + ld hl, (MAXX) + or a + sbc hl, de + ld (S_POSN), hl ; saves it again + ret + + + ECHO_E EQU 23682 + MAXX EQU ECHO_E ; Max X position + 1 + MAXY EQU MAXX + 1 ; Max Y position + 1 + + S_POSN EQU 23688 + POSX EQU S_POSN ; Current POS X + POSY EQU S_POSN + 1 ; Current POS Y + + ENDP + +#line 6 "print.asm" +#line 1 "cls.asm" + + ; JUMPS directly to spectrum CLS + ; This routine does not clear lower screen + + ;CLS EQU 0DAFh + + ; Our faster implementation + + + +CLS: + PROC + + LOCAL COORDS + LOCAL __CLS_SCR + LOCAL ATTR_P + LOCAL SCREEN + + ld hl, 0 + ld (COORDS), hl + ld hl, 1821h + ld (S_POSN), hl +__CLS_SCR: + ld hl, SCREEN + ld (hl), 0 + ld d, h + ld e, l + inc de + ld bc, 6144 + ldir + + ; Now clear attributes + + ld a, (ATTR_P) + ld (hl), a + ld bc, 767 + ldir + ret + + COORDS EQU 23677 + SCREEN EQU 16384 ; Default start of the screen (can be changed) + ATTR_P EQU 23693 + ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address + + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines + ; to get the start of the screen + ENDP + +#line 7 "print.asm" +#line 1 "in_screen.asm" + + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 3 "in_screen.asm" + +__IN_SCREEN: + ; Returns NO carry if current coords (D, E) + ; are OUT of the screen limits (MAXX, MAXY) + + PROC + LOCAL __IN_SCREEN_ERR + + ld hl, MAXX + ld a, e + cp (hl) + jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + + ld a, d + inc hl + cp (hl) + ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + ;; ret + ret c ; Return if carry (OK) + +__IN_SCREEN_ERR: +__OUT_OF_SCREEN_ERR: + ; Jumps here if out of screen + ld a, ERROR_OutOfScreen + jp __STOP ; Saves error code and exits + + ENDP +#line 8 "print.asm" +#line 1 "table_jump.asm" + + +JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A + add a, a + +JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE + ld e, a + ld d, 0 + +JUMP_HL_PLUS_DE: ; Does JP (HL + DE) + add hl, de + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl +CALL_HL: + jp (hl) + +#line 9 "print.asm" +#line 1 "ink.asm" + + ; Sets ink color in ATTR_P permanently +; Parameter: Paper color in A register + +#line 1 "const.asm" + + ; Global constants + + P_FLAG EQU 23697 + FLAGS2 EQU 23681 + ATTR_P EQU 23693 ; permanet ATTRIBUTES + ATTR_T EQU 23695 ; temporary ATTRIBUTES + CHARS EQU 23606 ; Pointer to ROM/RAM Charset + UDG EQU 23675 ; Pointer to UDG Charset + MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars + +#line 5 "ink.asm" + +INK: + PROC + LOCAL __SET_INK + LOCAL __SET_INK2 + + ld de, ATTR_P + +__SET_INK: + cp 8 + jr nz, __SET_INK2 + + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + or 7 ; Set bits 0,1,2 to enable transparency + ld (de), a + ret + +__SET_INK2: + ; Another entry. This will set the ink color at location pointer by DE + and 7 ; # Gets color mod 8 + ld b, a ; Saves the color + ld a, (de) + and 0F8h ; Clears previous value + or b + ld (de), a + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + and 0F8h ; Reset bits 0,1,2 sign to disable transparency + ld (de), a ; Store new attr + ret + + ; Sets the INK color passed in A register in the ATTR_T variable +INK_TMP: + ld de, ATTR_T + jp __SET_INK + + ENDP + +#line 10 "print.asm" +#line 1 "paper.asm" + + ; Sets paper color in ATTR_P permanently +; Parameter: Paper color in A register + + + +PAPER: + PROC + LOCAL __SET_PAPER + LOCAL __SET_PAPER2 + + ld de, ATTR_P + +__SET_PAPER: + cp 8 + jr nz, __SET_PAPER2 + inc de + ld a, (de) + or 038h + ld (de), a + ret + + ; Another entry. This will set the paper color at location pointer by DE +__SET_PAPER2: + and 7 ; # Remove + rlca + rlca + rlca ; a *= 8 + + ld b, a ; Saves the color + ld a, (de) + and 0C7h ; Clears previous value + or b + ld (de), a + inc de ; Points to MASK_T or MASK_P accordingly + ld a, (de) + and 0C7h ; Resets bits 3,4,5 + ld (de), a + ret + + + ; Sets the PAPER color passed in A register in the ATTR_T variable +PAPER_TMP: + ld de, ATTR_T + jp __SET_PAPER + ENDP + +#line 11 "print.asm" +#line 1 "flash.asm" + + ; Sets flash flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +FLASH: + ld de, ATTR_P +__SET_FLASH: + ; Another entry. This will set the flash flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + ld b, a ; Saves the color + ld a, (de) + and 07Fh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the FLASH flag passed in A register in the ATTR_T variable +FLASH_TMP: + ld de, ATTR_T + jr __SET_FLASH + +#line 12 "print.asm" +#line 1 "bright.asm" + + ; Sets bright flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +BRIGHT: + ld de, ATTR_P + +__SET_BRIGHT: + ; Another entry. This will set the bright flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + rrca + ld b, a ; Saves the color + ld a, (de) + and 0BFh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable +BRIGHT_TMP: + ld de, ATTR_T + jr __SET_BRIGHT + +#line 13 "print.asm" +#line 1 "over.asm" + + ; Sets OVER flag in P_FLAG permanently +; Parameter: OVER flag in bit 0 of A register +#line 1 "copy_attr.asm" + + + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" + + + +COPY_ATTR: + ; Just copies current permanent attribs to temporal attribs + ; and sets print mode + PROC + + LOCAL INVERSE1 + LOCAL __REFRESH_TMP + + INVERSE1 EQU 02Fh + + ld hl, (ATTR_P) + ld (ATTR_T), hl + + ld hl, FLAGS2 + call __REFRESH_TMP + + ld hl, P_FLAG + call __REFRESH_TMP + + +__SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) + + + LOCAL TABLE + LOCAL CONT2 + + rra ; Over bit to carry + ld a, (FLAGS2) + rla ; Over bit in bit 1, Over2 bit in bit 2 + and 3 ; Only bit 0 and 1 (OVER flag) + + ld c, a + ld b, 0 + + ld hl, TABLE + add hl, bc + ld a, (hl) + ld (PRINT_MODE), a + + ld hl, (P_FLAG) + xor a ; NOP -> INVERSE0 + bit 2, l + jr z, CONT2 + ld a, INVERSE1 ; CPL -> INVERSE1 + +CONT2: + ld (INVERSE_MODE), a + ret + +TABLE: + nop ; NORMAL MODE + xor (hl) ; OVER 1 MODE + and (hl) ; OVER 2 MODE + or (hl) ; OVER 3 MODE + +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" + +__REFRESH_TMP: + ld a, (hl) + and 10101010b + ld c, a + rra + or c + ld (hl), a + ret + + ENDP + +#line 4 "over.asm" + + +OVER: + PROC + + ld c, a ; saves it for later + and 2 + ld hl, FLAGS2 + res 1, (HL) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 ; # Convert to 0/1 + add a, a; # Shift left 1 bit for permanent + + ld hl, P_FLAG + res 1, (hl) + or (hl) + ld (hl), a + ret + + ; Sets OVER flag in P_FLAG temporarily +OVER_TMP: + ld c, a ; saves it for later + and 2 ; gets bit 1; clears carry + rra + ld hl, FLAGS2 + res 0, (hl) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 + ld hl, P_FLAG + res 0, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 14 "print.asm" +#line 1 "inverse.asm" + + ; Sets INVERSE flag in P_FLAG permanently +; Parameter: INVERSE flag in bit 0 of A register + + + +INVERSE: + PROC + + and 1 ; # Convert to 0/1 + add a, a; # Shift left 3 bits for permanent + add a, a + add a, a + ld hl, P_FLAG + res 3, (hl) + or (hl) + ld (hl), a + ret + + ; Sets INVERSE flag in P_FLAG temporarily +INVERSE_TMP: + and 1 + add a, a + add a, a; # Shift left 2 bits for temporary + ld hl, P_FLAG + res 2, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 15 "print.asm" +#line 1 "bold.asm" + + ; Sets BOLD flag in P_FLAG permanently +; Parameter: BOLD flag in bit 0 of A register + + +BOLD: + PROC + + and 1 + rlca + rlca + rlca + ld hl, FLAGS2 + res 3, (HL) + or (hl) + ld (hl), a + ret + + ; Sets BOLD flag in P_FLAG temporarily +BOLD_TMP: + and 1 + rlca + rlca + ld hl, FLAGS2 + res 2, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 16 "print.asm" +#line 1 "italic.asm" + + ; Sets ITALIC flag in P_FLAG permanently +; Parameter: ITALIC flag in bit 0 of A register + + +ITALIC: + PROC + + and 1 + rrca + rrca + rrca + ld hl, FLAGS2 + res 5, (HL) + or (hl) + ld (hl), a + ret + + ; Sets ITALIC flag in P_FLAG temporarily +ITALIC_TMP: + and 1 + rrca + rrca + rrca + rrca + ld hl, FLAGS2 + res 4, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 17 "print.asm" + +#line 1 "attr.asm" + + ; Attribute routines +; vim:ts=4:et:sw: + + + + + + + +__ATTR_ADDR: + ; calc start address in DE (as (32 * d) + e) + ; Contributed by Santiago Romero at http://www.speccy.org + ld h, 0 ; 7 T-States + ld a, d ; 4 T-States + add a, a ; a * 2 ; 4 T-States + add a, a ; a * 4 ; 4 T-States + ld l, a ; HL = A * 4 ; 4 T-States + + add hl, hl ; HL = A * 8 ; 15 T-States + add hl, hl ; HL = A * 16 ; 15 T-States + add hl, hl ; HL = A * 32 ; 15 T-States + + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) + add hl, de + + ld de, (SCREEN_ADDR) ; Adds the screen address + add hl, de + + ; Return current screen address in HL + ret + + + ; Sets the attribute at a given screen coordinate (D, E). + ; The attribute is taken from the ATTR_T memory variable + ; Used by PRINT routines +SET_ATTR: + + ; Checks for valid coords + call __IN_SCREEN + ret nc + +__SET_ATTR: + ; Internal __FASTCALL__ Entry used by printing routines + PROC + + call __ATTR_ADDR + ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T + + ld a, d + and (hl) + ld c, a ; C = current screen color, masked + + ld a, d + cpl ; Negate mask + and e ; Mask current attributes + or c ; Mix them + ld (hl), a ; Store result in screen + + ret + + ENDP + + +#line 19 "print.asm" + + ; Putting a comment starting with @INIT
+ ; will make the compiler to add a CALL to
+ ; It is useful for initialization routines. + + +__PRINT_INIT: ; To be called before program starts (initializes library) + PROC + + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + + ld hl, 1821h + ld (MAXX), hl ; Sets current maxX and maxY + + xor a + ld (FLAGS2), a + + ret + + +__PRINTCHAR: ; Print character store in accumulator (A register) + ; Modifies H'L', B'C', A'F', D'E', A + + LOCAL PO_GR_1 + + LOCAL __PRCHAR + LOCAL __PRINT_CONT + LOCAL __PRINT_CONT2 + LOCAL __PRINT_JUMP + LOCAL __SRCADDR + LOCAL __PRINT_UDG + LOCAL __PRGRAPH + LOCAL __PRINT_START + + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 + +__PRINT_JUMP: + jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively + +__PRINT_START: + cp ' ' + jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones + + exx ; Switch to alternative registers + ex af, af' ; Saves a value (char to print) for later + + call __LOAD_S_POSN + + ; At this point we have the new coord + ld hl, (SCREEN_ADDR) + + ld a, d + ld c, a ; Saves it for later + + and 0F8h ; Masks 3 lower bit ; zy + ld d, a + + ld a, c ; Recovers it + and 07h ; MOD 7 ; y1 + rrca + rrca + rrca + + or e + ld e, a + add hl, de ; HL = Screen address + DE + ex de, hl ; DE = Screen address + + ex af, af' + + cp 80h ; Is it an UDG or a ? + jp c, __SRCADDR + + cp 90h + jp nc, __PRINT_UDG + + ; Print a 8 bit pattern (80h to 8Fh) + + ld b, a + call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 + ld hl, MEM0 + jp __PRGRAPH + + PO_GR_1 EQU 0B38h + +__PRINT_UDG: + sub 90h ; Sub ASC code + ld bc, (UDG) + jp __PRGRAPH0 + + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source +__SRCADDR: + ld bc, (CHARS) + +__PRGRAPH0: + add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org + ld l, a + ld h, 0 ; HL = a * 2 (accumulator) + add hl, hl + add hl, hl ; HL = a * 8 + add hl, bc ; HL = CHARS address + +__PRGRAPH: + ex de, hl ; HL = Write Address, DE = CHARS address + bit 2, (iy + $47) + call nz, __BOLD + bit 4, (iy + $47) + call nz, __ITALIC + ld b, 8 ; 8 bytes per char +__PRCHAR: + ld a, (de) ; DE *must* be ALWAYS source, and HL destiny + +PRINT_MODE: ; Which operation is used to write on the screen + ; Set it with: + ; LD A, + ; LD (PRINT_MODE), A + ; + ; Available opertions: + ; NORMAL: 0h --> NOP ; OVER 0 + ; XOR : AEh --> XOR (HL) ; OVER 1 + ; OR : B6h --> OR (HL) ; PUTSPRITE + ; AND : A6h --> AND (HL) ; PUTMASK + nop ; + +INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 + nop ; 2F -> CPL -> INVERSE 1 + + ld (hl), a + + inc de + inc h ; Next line + djnz __PRCHAR + + call __LOAD_S_POSN + push de + call __SET_ATTR + pop de + inc e ; COL = COL + 1 + ld hl, (MAXX) + ld a, e + dec l ; l = MAXX + cp l ; Lower than max? + jp c, __PRINT_CONT; Nothing to do + call __PRINT_EOL1 + exx ; counteracts __PRINT_EOL1 exx + jp __PRINT_CONT2 + +__PRINT_CONT: + call __SAVE_S_POSN + +__PRINT_CONT2: + exx + ret + + ; ------------- SPECIAL CHARS (< 32) ----------------- + +__PRINT_SPECIAL: ; Jumps here if it is a special char + exx + ld hl, __PRINT_TABLE + jp JUMP_HL_PLUS_2A + + +PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence + exx + +__PRINT_0Dh: ; Called WHEN printing CHR$(13) + call __LOAD_S_POSN + +__PRINT_EOL1: ; Another entry called from PRINT when next line required + ld e, 0 + +__PRINT_EOL2: + ld a, d + inc a + +__PRINT_AT1_END: + ld hl, (MAXY) + cp l + jr c, __PRINT_EOL_END ; Carry if (MAXY) < d + xor a + +__PRINT_EOL_END: + ld d, a + +__PRINT_AT2_END: + call __SAVE_S_POSN + exx + ret + +__PRINT_COM: + exx + push hl + push de + push bc + call PRINT_COMMA + pop bc + pop de + pop hl + ret + +__PRINT_TAB: + ld hl, __PRINT_TAB1 + jp __PRINT_SET_STATE + +__PRINT_TAB1: + ld (MEM0), a + ld hl, __PRINT_TAB2 + ld (PRINT_JUMP_STATE), hl + ret + +__PRINT_TAB2: + ld a, (MEM0) ; Load tab code (ignore the current one) + push hl + push de + push bc + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + call PRINT_TAB + pop bc + pop de + pop hl + ret + +__PRINT_NOP: +__PRINT_RESTART: + ld hl, __PRINT_START + jp __PRINT_SET_STATE + +__PRINT_AT: + ld hl, __PRINT_AT1 + +__PRINT_SET_STATE: + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + exx + ret + +__PRINT_AT1: ; Jumps here if waiting for 1st parameter + exx + ld hl, __PRINT_AT2 + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + jp __PRINT_AT1_END + +__PRINT_AT2: + exx + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + ld e, a + ld hl, (MAXX) + cp (hl) + jr c, __PRINT_AT2_END + jr __PRINT_EOL1 + +__PRINT_DEL: + call __LOAD_S_POSN ; Gets current screen position + dec e + ld a, -1 + cp e + jp nz, __PRINT_AT2_END + ld hl, (MAXX) + ld e, l + dec e + dec e + dec d + cp d + jp nz, __PRINT_AT2_END + ld d, h + dec d + jp __PRINT_AT2_END + +__PRINT_INK: + ld hl, __PRINT_INK2 + jp __PRINT_SET_STATE + +__PRINT_INK2: + exx + call INK_TMP + jp __PRINT_RESTART + +__PRINT_PAP: + ld hl, __PRINT_PAP2 + jp __PRINT_SET_STATE + +__PRINT_PAP2: + exx + call PAPER_TMP + jp __PRINT_RESTART + +__PRINT_FLA: + ld hl, __PRINT_FLA2 + jp __PRINT_SET_STATE + +__PRINT_FLA2: + exx + call FLASH_TMP + jp __PRINT_RESTART + +__PRINT_BRI: + ld hl, __PRINT_BRI2 + jp __PRINT_SET_STATE + +__PRINT_BRI2: + exx + call BRIGHT_TMP + jp __PRINT_RESTART + +__PRINT_INV: + ld hl, __PRINT_INV2 + jp __PRINT_SET_STATE + +__PRINT_INV2: + exx + call INVERSE_TMP + jp __PRINT_RESTART + +__PRINT_OVR: + ld hl, __PRINT_OVR2 + jp __PRINT_SET_STATE + +__PRINT_OVR2: + exx + call OVER_TMP + jp __PRINT_RESTART + +__PRINT_BOLD: + ld hl, __PRINT_BOLD2 + jp __PRINT_SET_STATE + +__PRINT_BOLD2: + exx + call BOLD_TMP + jp __PRINT_RESTART + +__PRINT_ITA: + ld hl, __PRINT_ITA2 + jp __PRINT_SET_STATE + +__PRINT_ITA2: + exx + call ITALIC_TMP + jp __PRINT_RESTART + + +__BOLD: + push hl + ld hl, MEM0 + ld b, 8 +__BOLD_LOOP: + ld a, (de) + ld c, a + rlca + or c + ld (hl), a + inc hl + inc de + djnz __BOLD_LOOP + pop hl + ld de, MEM0 + ret + + +__ITALIC: + push hl + ld hl, MEM0 + ex de, hl + ld bc, 8 + ldir + ld hl, MEM0 + srl (hl) + inc hl + srl (hl) + inc hl + srl (hl) + inc hl + inc hl + inc hl + sla (hl) + inc hl + sla (hl) + inc hl + sla (hl) + pop hl + ld de, MEM0 + ret + +PRINT_COMMA: + call __LOAD_S_POSN + ld a, e + and 16 + add a, 16 + +PRINT_TAB: + PROC + LOCAL LOOP, CONTINUE + + inc a + call __LOAD_S_POSN ; e = current row + ld d, a + ld a, e + cp 21h + jr nz, CONTINUE + ld e, -1 +CONTINUE: + ld a, d + inc e + sub e ; A = A - E + and 31 ; + ret z ; Already at position E + ld b, a +LOOP: + ld a, ' ' + call __PRINTCHAR + djnz LOOP + ret + ENDP + +PRINT_AT: ; CHanges cursor to ROW, COL + ; COL in A register + ; ROW in stack + + pop hl ; Ret address + ex (sp), hl ; callee H = ROW + ld l, a + ex de, hl + + call __IN_SCREEN + ret nc ; Return if out of screen + + jp __SAVE_S_POSN + + LOCAL __PRINT_COM + LOCAL __BOLD + LOCAL __BOLD_LOOP + LOCAL __ITALIC + LOCAL __PRINT_EOL1 + LOCAL __PRINT_EOL2 + LOCAL __PRINT_AT1 + LOCAL __PRINT_AT2 + LOCAL __PRINT_AT2_END + LOCAL __PRINT_BOLD + LOCAL __PRINT_BOLD2 + LOCAL __PRINT_ITA + LOCAL __PRINT_ITA2 + LOCAL __PRINT_INK + LOCAL __PRINT_PAP + LOCAL __PRINT_SET_STATE + LOCAL __PRINT_TABLE + LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 + +__PRINT_TABLE: ; Jump table for 0 .. 22 codes + + DW __PRINT_NOP ; 0 + DW __PRINT_NOP ; 1 + DW __PRINT_NOP ; 2 + DW __PRINT_NOP ; 3 + DW __PRINT_NOP ; 4 + DW __PRINT_NOP ; 5 + DW __PRINT_COM ; 6 COMMA + DW __PRINT_NOP ; 7 + DW __PRINT_DEL ; 8 DEL + DW __PRINT_NOP ; 9 + DW __PRINT_NOP ; 10 + DW __PRINT_NOP ; 11 + DW __PRINT_NOP ; 12 + DW __PRINT_0Dh ; 13 + DW __PRINT_BOLD ; 14 + DW __PRINT_ITA ; 15 + DW __PRINT_INK ; 16 + DW __PRINT_PAP ; 17 + DW __PRINT_FLA ; 18 + DW __PRINT_BRI ; 19 + DW __PRINT_INV ; 20 + DW __PRINT_OVR ; 21 + DW __PRINT_AT ; 22 AT + DW __PRINT_TAB ; 23 TAB + + ENDP + + +#line 92 "readokup.bas" +#line 1 "printf.asm" + +#line 1 "printstr.asm" + + + + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 5 "printstr.asm" + + ; PRINT command routine + ; Prints string pointed by HL + +PRINT_STR: +__PRINTSTR: ; __FASTCALL__ Entry to print_string + PROC + LOCAL __PRINT_STR_LOOP + LOCAL __PRINT_STR_END + + ld d, a ; Saves A reg (Flag) for later + + ld a, h + or l + ret z ; Return if the pointer is NULL + + push hl + + ld c, (hl) + inc hl + ld b, (hl) + inc hl ; BC = LEN(a$); HL = &a$ + +__PRINT_STR_LOOP: + ld a, b + or c + jr z, __PRINT_STR_END ; END if BC (counter = 0) + + ld a, (hl) + call __PRINTCHAR + inc hl + dec bc + jp __PRINT_STR_LOOP + +__PRINT_STR_END: + pop hl + ld a, d ; Recovers A flag + or a ; If not 0 this is a temporary string. Free it + ret z + jp __MEM_FREE ; Frees str from heap and return from there + +__PRINT_STR: + ; Fastcall Entry + ; It ONLY prints strings + ; HL = String start + ; BC = String length (Number of chars) + push hl ; Push str address for later + ld d, a ; Saves a FLAG + jp __PRINT_STR_LOOP + + ENDP + +#line 2 "printf.asm" +#line 1 "stackf.asm" + + ; ------------------------------------------------------------- + ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC + ; ------------------------------------------------------------- + + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) + __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) + +__FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) + ; Second argument to push into the stack calculator is popped out of the stack + ; Since the caller routine also receives the parameters into the top of the stack + ; four bytes must be removed from SP before pop them out + + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK + exx + pop hl ; Caller-Caller return addr + exx + pop hl ; Caller return addr + + pop af + pop de + pop bc + + push hl ; Caller return addr + exx + push hl ; Caller-Caller return addr + exx + + jp __FPSTACK_PUSH + + +__FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK + ; This format is specified in the ZX 48K Manual + ; You can push a 16 bit signed integer as + ; 0 SS LL HH 0, being SS the sign and LL HH the low + ; and High byte respectively + ld a, h + rla ; sign to Carry + sbc a, a ; 0 if positive, FF if negative + ld e, a + ld d, l + ld c, h + xor a + ld b, a + jp __FPSTACK_PUSH +#line 3 "printf.asm" + + +__PRINTF: ; Prints a Fixed point Number stored in C ED LH + PROC + + LOCAL RECLAIM2 + LOCAL STK_END + STK_END EQU 5C65h + + ld hl, (ATTR_T) + push hl ; Saves ATTR_T since BUG ROM changes it + + ld hl, (STK_END) + push hl ; Stores STK_END + + call __FPSTACK_PUSH ; Push number into stack + rst 28h ; # Rom Calculator + defb 2Eh ; # STR$(x) + defb 38h ; # END CALC + call __FPSTACK_POP ; Recovers string parameters to A ED CB + + pop hl + ld (STK_END), hl ; Balance STK_END to avoid STR$ bug + + pop hl + ld (ATTR_T), hl ; Restores ATTR_T + + ex de, hl ; String position now in HL + + push bc + xor a ; Avoid the str to be FREED from heap + call __PRINT_STR + pop bc + inc bc + + jp RECLAIM2 ; Frees TMP Memory + + RECLAIM2 EQU 19E8h + + ENDP + +#line 93 "readokup.bas" +#line 1 "printf16.asm" + +#line 1 "printnum.asm" + + + + +__PRINTU_START: + PROC + + LOCAL __PRINTU_CONT + + ld a, b + or a + jp nz, __PRINTU_CONT + + ld a, '0' + jp __PRINT_DIGIT + + +__PRINTU_CONT: + pop af + push bc + call __PRINT_DIGIT + pop bc + djnz __PRINTU_CONT + ret + + ENDP + + +__PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers + ld a, '-' + jp __PRINT_DIGIT + + __PRINT_DIGIT EQU __PRINTCHAR ; PRINTS the char in A register, and puts its attrs + + +#line 2 "printf16.asm" +#line 1 "printi16.asm" + + +#line 1 "div16.asm" + + ; 16 bit division and modulo functions + ; for both signed and unsigned values + +#line 1 "neg16.asm" + + ; Negates HL value (16 bit) +__ABS16: + bit 7, h + ret z + +__NEGHL: + ld a, l ; HL = -HL + cpl + ld l, a + ld a, h + cpl + ld h, a + inc hl + ret + +#line 5 "div16.asm" + +__DIVU16: ; 16 bit unsigned division + ; HL = Dividend, Stack Top = Divisor + + ; -- OBSOLETE ; Now uses FASTCALL convention + ; ex de, hl + ; pop hl ; Return address + ; ex (sp), hl ; CALLEE Convention + +__DIVU16_FAST: + ld a, h + ld c, l + ld hl, 0 + ld b, 16 + +__DIV16LOOP: + sll c + rla + adc hl,hl + sbc hl,de + jr nc, __DIV16NOADD + add hl,de + dec c + +__DIV16NOADD: + djnz __DIV16LOOP + + ex de, hl + ld h, a + ld l, c + + ret ; HL = quotient, DE = Mudulus + + + +__MODU16: ; 16 bit modulus + ; HL = Dividend, Stack Top = Divisor + + ;ex de, hl + ;pop hl + ;ex (sp), hl ; CALLEE Convention + + call __DIVU16_FAST + ex de, hl ; hl = reminder (modulus) + ; de = quotient + + ret + + +__DIVI16: ; 16 bit signed division + ; --- The following is OBSOLETE --- + ; ex de, hl + ; pop hl + ; ex (sp), hl ; CALLEE Convention + +__DIVI16_FAST: + ld a, d + xor h + ex af, af' ; BIT 7 of a contains result + + bit 7, d ; DE is negative? + jr z, __DIVI16A + + ld a, e ; DE = -DE + cpl + ld e, a + ld a, d + cpl + ld d, a + inc de + +__DIVI16A: + bit 7, h ; HL is negative? + call nz, __NEGHL + +__DIVI16B: + call __DIVU16_FAST + ex af, af' + + or a + ret p ; return if positive + jp __NEGHL + + +__MODI16: ; 16 bit modulus + ; HL = Dividend, Stack Top = Divisor + + ;ex de, hl + ;pop hl + ;ex (sp), hl ; CALLEE Convention + + call __DIVI16_FAST + ex de, hl ; hl = reminder (modulus) + ; de = quotient + + ret + +#line 3 "printi16.asm" + + + +__PRINTI16: ; Prints a 16bits signed in HL + ; Converts 16 to 32 bits + PROC + + LOCAL __PRINTU_LOOP + ld a, h + or a + + jp p, __PRINTU16 + + call __PRINT_MINUS + call __NEGHL + +__PRINTU16: + + ld b, 0 +__PRINTU_LOOP: + ld a, h + or l + jp z, __PRINTU_START + + push bc + ld de, 10 + call __DIVU16_FAST ; Divides by DE. DE = MODULUS at exit. Since < 256, E = Modulus + pop bc + + ld a, e + or '0' ; Stores ASCII digit (must be print in reversed order) + push af + inc b + jp __PRINTU_LOOP ; Uses JP in loops + + ENDP + +#line 3 "printf16.asm" +#line 1 "neg32.asm" + +__ABS32: + bit 7, d + ret z + +__NEG32: ; Negates DEHL (Two's complement) + ld a, l + cpl + ld l, a + + ld a, h + cpl + ld h, a + + ld a, e + cpl + ld e, a + + ld a, d + cpl + ld d, a + + inc l + ret nz + + inc h + ret nz + + inc de + ret + +#line 4 "printf16.asm" + +__PRINTF16: ; Prints a 32bit 16.16 fixed point number + PROC + + LOCAL __PRINT_FIX_LOOP + LOCAL __PRINTF16_2 + + bit 7, d + jr z, __PRINTF16_2 + call __NEG32 + call __PRINT_MINUS + +__PRINTF16_2: + push hl + ex de, hl + call __PRINTU16 ; Prints integer part + pop hl + + ld a, h + or l + ret z ; Returns if integer + + push hl + ld a, '.' + call __PRINT_DIGIT ; Prints decimal point + pop hl + +__PRINT_FIX_LOOP: + ld a, h + or l + ret z ; Returns if no more decimals + + xor a + ld d, h + ld e, l + ; Fast NUM * 10 multiplication + add hl, hl ; + adc a, a ; AHL = AHL * 2 (= X * 2) + add hl, hl ; + adc a, a ; AHL = AHL * 2 (= X * 4) + + add hl, de ; + adc a, 0 ; AHL = AHL + DE (= X * 5) + add hl, hl + adc a, a ; AHL = AHL * 2 (= X * 10) + + push hl + or '0' + call __PRINT_DIGIT + pop hl + jp __PRINT_FIX_LOOP + + ENDP + +#line 94 "readokup.bas" + +#line 1 "printi32.asm" + + + +#line 1 "div32.asm" + + + + ; --------------------------------------------------------- +__DIVU32: ; 32 bit unsigned division + ; DEHL = Dividend, Stack Top = Divisor + ; OPERANDS P = Dividend, Q = Divisor => OPERATION => P / Q + ; + ; Changes A, BC DE HL B'C' D'E' H'L' + ; --------------------------------------------------------- + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + +__DIVU32START: ; Performs D'E'H'L' / HLDE + ; Now switch to DIVIDEND = B'C'BC / DIVISOR = D'E'DE (A / B) + push de ; push Lowpart(Q) + ex de, hl ; DE = HL + ld hl, 0 + exx + ld b, h + ld c, l + pop hl + push de + ex de, hl + ld hl, 0 ; H'L'HL = 0 + exx + pop bc ; Pop HightPart(B) => B = B'C'BC + exx + + ld a, 32 ; Loop count + +__DIV32LOOP: + sll c ; B'C'BC << 1 ; Output most left bit to carry + rl b + exx + rl c + rl b + exx + + adc hl, hl + exx + adc hl, hl + exx + + sbc hl,de + exx + sbc hl,de + exx + jp nc, __DIV32NOADD ; use JP inside a loop for being faster + + add hl, de + exx + adc hl, de + exx + dec bc + +__DIV32NOADD: + dec a + jp nz, __DIV32LOOP ; use JP inside a loop for being faster + ; At this point, quotient is stored in B'C'BC and the reminder in H'L'HL + + push hl + exx + pop de + ex de, hl ; D'E'H'L' = 32 bits modulus + push bc + exx + pop de ; DE = B'C' + ld h, b + ld l, c ; DEHL = quotient D'E'H'L' = Modulus + + ret ; DEHL = quotient, D'E'H'L' = Modulus + + + +__MODU32: ; 32 bit modulus for 32bit unsigned division + ; DEHL = Dividend, Stack Top = Divisor (DE, HL) + + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + + call __DIVU32START ; At return, modulus is at D'E'H'L' + +__MODU32START: + + exx + push de + push hl + + exx + pop hl + pop de + + ret + + +__DIVI32: ; 32 bit signed division + ; DEHL = Dividend, Stack Top = Divisor + ; A = Dividend, B = Divisor => A / B + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + +__DIVI32START: + exx + ld a, d ; Save sign + ex af, af' + bit 7, d ; Negative? + call nz, __NEG32 ; Negates DEHL + + exx ; Now works with H'L'D'E' + ex af, af' + xor h + ex af, af' ; Stores sign of the result for later + + bit 7, h ; Negative? + ex de, hl ; HLDE = DEHL + call nz, __NEG32 + ex de, hl + + call __DIVU32START + ex af, af' ; Recovers sign + and 128 ; positive? + ret z + + jp __NEG32 ; Negates DEHL and returns from there + + +__MODI32: ; 32bits signed division modulus + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + + call __DIVI32START + jp __MODU32START + +#line 4 "printi32.asm" + + + +__PRINTI32: + ld a, d + or a + jp p, __PRINTU32 + + call __PRINT_MINUS + call __NEG32 + +__PRINTU32: + PROC + LOCAL __PRINTU_LOOP + + ld b, 0 ; Counter + +__PRINTU_LOOP: + ld a, h + or l + or d + or e + jp z, __PRINTU_START + + push bc + + ld bc, 0 + push bc + ld bc, 10 + push bc ; Push 00 0A (10 Dec) into the stack = divisor + + call __DIVU32 ; Divides by 32. D'E'H'L' contains modulo (L' since < 10) + pop bc + + exx + ld a, l + or '0' ; Stores ASCII digit (must be print in reversed order) + push af + exx + inc b + jp __PRINTU_LOOP ; Uses JP in loops + + ENDP + +#line 96 "readokup.bas" +#line 1 "printi8.asm" + + +#line 1 "div8.asm" + + ; -------------------------------- +__DIVU8: ; 8 bit unsigned integer division + ; Divides (Top of stack, High Byte) / A + pop hl ; -------------------------------- + ex (sp), hl ; CALLEE + +__DIVU8_FAST: ; Does A / H + ld l, h + ld h, a ; At this point do H / L + + ld b, 8 + xor a ; A = 0, Carry Flag = 0 + +__DIV8LOOP: + sla h + rla + cp l + jr c, __DIV8NOSUB + sub l + inc h + +__DIV8NOSUB: + djnz __DIV8LOOP + + ld l, a ; save remainder + ld a, h ; + + ret ; a = Quotient, + + + ; -------------------------------- +__DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A + pop hl ; -------------------------------- + ex (sp), hl + +__DIVI8_FAST: + ld e, a ; store operands for later + ld c, h + + or a ; negative? + jp p, __DIV8A + neg ; Make it positive + +__DIV8A: + ex af, af' + ld a, h + or a + jp p, __DIV8B + neg + ld h, a ; make it positive + +__DIV8B: + ex af, af' + + call __DIVU8_FAST + + ld a, c + xor l ; bit 7 of A = 1 if result is negative + + ld a, h ; Quotient + ret p ; return if positive + + neg + ret + + +__MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) + pop hl + ex (sp), hl ; CALLEE + +__MODU8_FAST: ; __FASTCALL__ entry + call __DIVU8_FAST + ld a, l ; Remainder + + ret ; a = Modulus + + +__MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) + pop hl + ex (sp), hl ; CALLEE + +__MODI8_FAST: ; __FASTCALL__ entry + call __DIVI8_FAST + ld a, l ; remainder + + ret ; a = Modulus + +#line 3 "printi8.asm" + +__PRINTI8: ; Prints an 8 bits number in Accumulator (A) + ; Converts 8 to 32 bits + or a + jp p, __PRINTU8 + + push af + call __PRINT_MINUS + pop af + neg + +__PRINTU8: + PROC + + LOCAL __PRINTU_LOOP + + ld b, 0 ; Counter + +__PRINTU_LOOP: + or a + jp z, __PRINTU_START + + push bc + ld h, 10 + call __DIVU8_FAST ; Divides by 10. D'E'H'L' contains modulo (L' since < 10) + pop bc + + ld a, l + or '0' ; Stores ASCII digit (must be print in reversed order) + push af + ld a, h + inc b + jp __PRINTU_LOOP ; Uses JP in loops + + ENDP + +#line 97 "readokup.bas" +#line 1 "printu16.asm" + + + +#line 98 "readokup.bas" +#line 1 "printu32.asm" + + + +#line 99 "readokup.bas" +#line 1 "printu8.asm" + + + +#line 100 "readokup.bas" +#line 1 "read_restore.asm" + + ;; This implements READ & RESTORE functions + ;; Reads a new element from the DATA Address code + ;; Updates the DATA_ADDR read ptr for the next read + + ;; Data codification is 1 byte for type followed by data bytes + ;; Byte type is encoded as follows + +;; 00: End of data +;; 01: String +;; 02: Byte +;; 03: Ubyte +;; 04: Integer +;; 05: UInteger +;; 06: Long +;; 07: ULong +;; 08: Fixed +;; 09: Float + + ;; bit7 is set for a parameter-less function + ;; In that case, the next two bytes are the ptr of the function to jump + + +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 24 "read_restore.asm" +#line 1 "iload32.asm" + + ; __FASTCALL__ routine which + ; loads a 32 bits integer into DE,HL + ; stored at position pointed by POINTER HL + ; DE,HL <-- (HL) + +__ILOAD32: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + ex de, hl + ret + +#line 25 "read_restore.asm" +#line 1 "iloadf.asm" + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- ((HL)) + +__ILOADF: + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- (HL) + +__LOADF: ; Loads a 40 bits FP number from address pointed by HL + ld a, (hl) + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld c, (hl) + inc hl + ld b, (hl) + ret + +#line 26 "read_restore.asm" +#line 1 "ftof16reg.asm" + +#line 1 "ftou32reg.asm" + + + +__FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + ; Output: DEHL 32 bit number (signed) + PROC + + LOCAL __IS_FLOAT + + or a + jr nz, __IS_FLOAT + ; Here if it is a ZX ROM Integer + + ld h, c + ld l, d + ld a, e ; Takes sign: FF = -, 0 = + + ld de, 0 + inc a + jp z, __NEG32 ; Negates if negative + ret + +__IS_FLOAT: ; Jumps here if it is a true floating point number + ld h, e + push hl ; Stores it for later (Contains Sign in H) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + ;ld a, c ; Get exponent + sub 128 ; Exponent -= 128 + jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + +__FTOU32REG_LOOP: + exx ; Shift C'B' E'D' << 1, output bit stays in Carry + sla d + rl e + rl b + rl c + + exx ; Shift DEHL << 1, inserting the carry on the right + rl l + rl h + rl e + rl d + + djnz __FTOU32REG_LOOP + +__FTOU32REG_END: + pop af ; Take the sign bit + or a ; Sets SGN bit to 1 if negative + jp m, __NEG32 ; Negates DEHL + + ret + + ENDP + + +__FTOU8: ; Converts float in C ED LH to Unsigned byte in A + call __FTOU32REG + ld a, l + ret + +#line 2 "ftof16reg.asm" + +__FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + + ld l, a ; Saves exponent for later + or d + or e + or b + or c + ld h, e + ret z ; Return if ZERO + + push hl ; Stores it for later (Contains sign in H, exponent in L) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + pop bc + + ld a, c ; Get exponent + sub 112 ; Exponent -= 128 + 16 + + push bc ; Saves sign in b again + + jp z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jp c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + 16 (we need to shift 16 bit more) + jp __FTOU32REG_LOOP ; proceed as an u32 integer + +#line 27 "read_restore.asm" +#line 1 "f16tofreg.asm" + + +#line 1 "u32tofreg.asm" + + +__I8TOFREG: + ld l, a + rlca + sbc a, a ; A = SGN(A) + ld h, a + ld e, a + ld d, a + +__I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) + ; to a Floating Point Number returned in (A ED CB) + + ld a, d + or a ; Test sign + + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __U32TOFREG ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + +__U8TOFREG: + ; Converts an unsigned 8 bit (A) to Floating point + ld l, a + ld h, 0 + ld e, h + ld d, h + +__U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in A ED CB + + PROC + + LOCAL __U32TOFREG_END + + ld a, d + or e + or h + or l + ld b, d + ld c, e ; Returns 00 0000 0000 if ZERO + ret z + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 128 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + +__U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG + exx + ld a, d ; B'C'D'E' == 0 ? + or e + or b + or c + jp z, __U32TOFREG_END ; We are done + + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry + rr c + rr d + rr e + exx + + rr e ; Shift EDCB >> 1, inserting the carry on the left + rr d + rr c + rr b + + inc l ; Increment exponent + jp __U32TOFREG_LOOP + + +__U32TOFREG_END: + exx + ld a, l ; Puts the exponent in a + res 7, e ; Sets the sign bit to 0 (positive) + + ret + ENDP + +#line 3 "f16tofreg.asm" + +__F16TOFREG: ; Converts a 16.16 signed fixed point (stored in DEHL) + ; to a Floating Point Number returned in (C ED CB) + PROC + + LOCAL __F16TOFREG2 + + ld a, d + or a ; Test sign + + jp p, __F16TOFREG2 ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __F16TOFREG2 ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + + +__F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in C DE HL + + ld a, d + or e + or h + or l + ld b, h + ld c, l + ret z ; Return 00 0000 0000 if 0 + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 112 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + jp __U32TOFREG_LOOP ; Proceed as an integer + + ENDP + +#line 28 "read_restore.asm" + + + + + + + + + + + + + + ;; Updates restore point to the given HL mem. address +__RESTORE: + PROC + LOCAL __DATA_ADDR + + ld (__DATA_ADDR), hl + ret + + ;; Reads a value from the DATA mem area and updates __DATA_ADDR ptr to the + ;; next item. On Out Of Data, restarts + ;; +__READ: + LOCAL read_restart, cont, cont2, table, no_func + LOCAL dynamic_cast, dynamic_cast2, dynamic_cast3, dynamic_cast4 + LOCAL _decode_table, coerce_to_int, coerce_to_int2, promote_to_i16 + LOCAL _from_i8, _from_u8 + LOCAL _from_i16, _from_u16 + LOCAL _from_i32, _from_u32 + LOCAL _from_fixed, __data_error + + push af ; type of data to read + ld hl, (__DATA_ADDR) +read_restart: + ld a, (hl) + or a ; 0 => OUT of data + jr nz, cont + ;; Signals out of data + + ld hl, __DATA__0 + ld (__DATA_ADDR), hl + jr read_restart ; Start again +cont: + and 0x80 + ld a, (hl) + push af + jp z, no_func ;; Loads data directly, not a function + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl +cont2: + ld de, dynamic_cast + push de ; ret address + jp (hl) ; "call (hl)" + + ;; Now tries to convert the given result to the expected type or raise an error +dynamic_cast: + exx + ex af, af' + pop af ; type READ + and 0x7F ; clear bit 7 + pop hl ; type requested by USER (type of the READ variable) + ld c, h ; save requested type (save it in register C) + cp h + exx + jr nz, dynamic_cast2 ; Types are identical? + ;; yes, they are + ex af, af' + ret + +dynamic_cast2: + cp 1 ; Requested a number, but read a string? + jr nz, dynamic_cast3 + call __MEM_FREE ; Frees str from memory + jr __data_error + +dynamic_cast3: + exx + ld b, a ; Read type + ld a, c ; Requested type + cp 1 + jr z, __data_error + cp b + jr c, dynamic_cast4 + ;; here the user expected type is "larger" than the read one + ld a, b + sub 2 + add a, a + ld l, a + ld h, 0 + ld de, _decode_table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl + ld a, c ; Requested type + exx + ret + +__data_error: + ;; When a data is read, but cannot be converted to the requested type + ;; that is, the user asked for a string and we read a number or vice versa + ld a, ERROR_InvalidArg + call __STOP ; The user expected a string, but read a number + xor a + ld h, a + ld l, a + ld e, a + ld d, a + ld b, a + ld c, a + ret + +_decode_table: + dw _from_i8 + dw _from_u8 + dw _from_i16 + dw _from_u16 + dw _from_i32 + dw _from_u32 + dw _from_fixed + +_from_i8: + cp 4 + jr nc, promote_to_i16 + ex af, af' + ret ;; Was from Byte to Ubyte + +promote_to_i16: + ex af, af' + ld l, a + rla + sbc a, a + ld h, a ; copy sgn to h + ex af, af' + jr _before_from_i16 + +_from_u8: + ex af, af' + ld l, a + ld h, 0 + ex af, af' + ;; Promoted to i16 + +_before_from_i16: +_from_i16: + cp 6 + ret c ;; from i16 to u16 + ;; Promote i16 to i32 + ex af, af' + ld a, h + rla + sbc a, a + ld e, a + ld d, a + ex af, af' +_from_i32: + cp 7 + ret z ;; From i32 to u32 + ret c ;; From u16 to i32 + cp 9 + jp z, __I32TOFREG +_from_u32: + cp 9 + jp z, __U32TOFREG + ex de, hl + ld hl, 0 + cp 8 + ret z +_from_fixed: ;; From fixed to float + jp __F16TOFREG +_from_u16: + ld de, 0 ; HL 0x0000 => 32 bits + jp _from_i32 + +dynamic_cast4: + ;; The user type is "shorter" than the read one + cp 8 ;; required type + jr c, before_to_int ;; required < fixed (f16) + ex af, af' + exx ;; Ok, we must convert from float to f16 + jp __FTOF16REG + +before_to_int: + ld a, b ;; read type + cp 8 ;; + jr nz, coerce_to_int ;; From float to int + ld a, c ;; user type + exx + ;; f16 to Long + ex de, hl + ld a, h + rla + sbc a, a + ld d, a + ld e, a + exx + jr coerce_to_int2 +coerce_to_int: + exx + ex af, af' + call __FTOU32REG + ex af, af' ; a contains user type + exx +coerce_to_int2: ; At this point we have an u/integer in hl + exx + cp 4 + ret nc ; Already done. Return the result + ld a, l ; Truncate to byte + ret + +no_func: + exx + ld de, dynamic_cast + push de ; Ret address + dec a ; 0 => string; 1, 2 => byte; 3, 4 => integer; 5, 6 => long, 7 => fixed; 8 => float + ld h, 0 + add a, a + ld l, a + ld de, table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl ; address to jump to + exx + inc hl + ret ; jp (sp) => jump to table[a - 1] + +table: + LOCAL __01_decode_string + LOCAL __02_decode_byte + LOCAL __03_decode_ubyte + LOCAL __04_decode_integer + LOCAL __05_decode_uinteger + LOCAL __06_decode_long + LOCAL __07_decode_ulong + LOCAL __08_decode_fixed + LOCAL __09_decode_float + + ;; 1 -> Decode string + ;; 2, 3 -> Decode Byte, UByte + ;; 4, 5 -> Decode Integer, UInteger + ;; 6, 7 -> Decode Long, ULong + ;; 8 -> Decode Fixed + ;; 9 -> Decode Float + dw __01_decode_string + dw __02_decode_byte + dw __03_decode_ubyte + dw __04_decode_integer + dw __05_decode_uinteger + dw __06_decode_long + dw __07_decode_ulong + dw __08_decode_fixed + dw __09_decode_float + +__01_decode_string: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl + jp __LOADSTR + +__02_decode_byte: +__03_decode_ubyte: + ld a, (hl) + inc hl + ld (__DATA_ADDR), hl + ret + +__04_decode_integer: +__05_decode_uinteger: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl + ex de, hl + ret + +__06_decode_long: +__07_decode_ulong: +__08_decode_fixed: + ld b, h + ld c, l + inc bc + inc bc + inc bc + inc bc + ld (__DATA_ADDR), bc + jp __ILOAD32 + +__09_decode_float: + call __LOADF + inc hl + ld (__DATA_ADDR), hl + ld h, a ; returns A in H; sets A free + ret + +__DATA_ADDR: ;; Stores current DATA ptr + dw __DATA__0 + ENDP + + + + + + + + + + +#line 101 "readokup.bas" +#line 1 "storef.asm" + +__PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) + push de + ex de, hl ; DE <- HL + push ix + pop hl ; HL <- IX + add hl, de ; HL <- IX + HL + pop de + +__ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register + ex af, af' + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex af, af' + +__STOREF: ; Stores the given FP number in A EDCB at address HL + ld (hl), a + inc hl + ld (hl), e + inc hl + ld (hl), d + inc hl + ld (hl), c + inc hl + ld (hl), b + ret + +#line 102 "readokup.bas" + +ZXBASIC_USER_DATA: +_i8: + DEFB 00 +_u8: + DEFB 00 +_i16: + DEFB 00, 00 +_u16: + DEFB 00, 00 +_i32: + DEFB 00, 00, 00, 00 +_u32: + DEFB 00, 00, 00, 00 +_f16: + DEFB 00, 00, 00, 00 +_flt: + DEFB 00, 00, 00, 00, 00 +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/readokup.bas b/tests/functional/readokup.bas new file mode 100644 index 000000000..14a0a95d9 --- /dev/null +++ b/tests/functional/readokup.bas @@ -0,0 +1,46 @@ +REM Type promoting in read DATA + +DIM i8 as Byte +DIM u8 as UByte +DIM i16 as Integer +DIM u16 as UInteger +DIM i32 as Long +DIM u32 as ULong +DIM f16 as Fixed +DIM flt as Float + +RESTORE +READ i8 +PRINT i8 + +RESTORE +READ u8 +PRINT u8 + +RESTORE +READ i16 +PRINT i16 + +RESTORE +READ u16 +PRINT u16 + +RESTORE +READ i32 +PRINT i32 + +RESTORE +READ u32 +PRINT u32 + +RESTORE +READ f16 +PRINT f16 + +RESTORE +READ flt +PRINT flt + +DATA -1 + + From c474e52f4d211dbdf94c20664667197aa51db8a8 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 6 Oct 2017 00:14:53 +0200 Subject: [PATCH 073/247] remove trailing newilines in output This ensures the same asm outut in python2 and python3 when including Windows asm files (windows EOLs sometimes are treated differently) --- tests/functional/00.asm | 2 +- tests/functional/02.asm | 2 +- tests/functional/03.asm | 2 +- tests/functional/04.asm | 2 +- tests/functional/05.asm | 2 +- tests/functional/06.asm | 2 +- tests/functional/07.asm | 2 +- tests/functional/08.asm | 2 +- tests/functional/09.asm | 2 +- tests/functional/10.asm | 2 +- tests/functional/11.asm | 2 +- tests/functional/12.asm | 2 +- tests/functional/13.asm | 2 +- tests/functional/15.asm | 2 +- tests/functional/16.asm | 2 +- tests/functional/17.asm | 2 +- tests/functional/18.asm | 2 +- tests/functional/19.asm | 136 +- tests/functional/20.asm | 2 +- tests/functional/21.asm | 10 +- tests/functional/22.asm | 2 +- tests/functional/25.asm | 12 +- tests/functional/26.asm | 2 +- tests/functional/27.asm | 394 +++--- tests/functional/28.asm | 404 +++--- tests/functional/29.asm | 488 ++++---- tests/functional/30.asm | 2 +- tests/functional/31.asm | 54 +- tests/functional/32.asm | 2 +- tests/functional/33.asm | 2 +- tests/functional/34.asm | 66 +- tests/functional/35.asm | 118 +- tests/functional/36.asm | 118 +- tests/functional/37.asm | 118 +- tests/functional/38.asm | 118 +- tests/functional/39.asm | 66 +- tests/functional/40.asm | 66 +- tests/functional/41.asm | 2 +- tests/functional/42.asm | 2 +- tests/functional/43.asm | 66 +- tests/functional/44.asm | 2 +- tests/functional/45.asm | 2 +- tests/functional/46.asm | 104 +- tests/functional/47.asm | 104 +- tests/functional/48.asm | 484 +++---- tests/functional/49.asm | 484 +++---- tests/functional/52.asm | 2 +- tests/functional/54.asm | 2 +- tests/functional/55.asm | 104 +- tests/functional/60.asm | 2 +- tests/functional/61.asm | 2 +- tests/functional/63.asm | 2 +- tests/functional/64.asm | 2 +- tests/functional/65.asm | 2 +- tests/functional/66.asm | 2 +- tests/functional/70.asm | 216 ++-- tests/functional/abs.asm | 2 +- tests/functional/abs32.asm | 28 +- tests/functional/add16.asm | 2 +- tests/functional/add16a.asm | 2 +- tests/functional/add16b.asm | 2 +- tests/functional/add32.asm | 2 +- tests/functional/add32a.asm | 2 +- tests/functional/add32b.asm | 2 +- tests/functional/add8.asm | 2 +- tests/functional/add8a.asm | 2 +- tests/functional/add8b.asm | 2 +- tests/functional/addf16.asm | 2 +- tests/functional/addf16a.asm | 2 +- tests/functional/addf16b.asm | 2 +- tests/functional/addstr.asm | 358 +++--- tests/functional/aloadstr0.asm | 288 ++--- tests/functional/aloadstr1.asm | 390 +++--- tests/functional/and16.asm | 12 +- tests/functional/and32.asm | 20 +- tests/functional/and8.asm | 10 +- tests/functional/arden2.asm | 408 +++--- tests/functional/array00.asm | 2 +- tests/functional/array01.asm | 2 +- tests/functional/array02.asm | 2 +- tests/functional/array03.asm | 104 +- tests/functional/array04.asm | 2 +- tests/functional/array05.asm | 2 +- tests/functional/array06.asm | 104 +- tests/functional/array07.asm | 498 ++++---- tests/functional/array08.asm | 514 ++++---- tests/functional/array09.asm | 496 ++++---- tests/functional/array10.asm | 104 +- tests/functional/array12.asm | 514 ++++---- tests/functional/arraycopy0.asm | 2 +- tests/functional/arraycopy1.asm | 2 +- tests/functional/arraycopy2.asm | 2 +- tests/functional/arraycopy3.asm | 2 +- tests/functional/arrlabels.asm | 2 +- tests/functional/arrlabels1.asm | 2 +- tests/functional/arrlabels10a.asm | 2 +- tests/functional/arrlabels10b.asm | 2 +- tests/functional/arrlabels2.asm | 2 +- tests/functional/arrlabels3.asm | 2 +- tests/functional/arrlabels4.asm | 2 +- tests/functional/arrlabels5.asm | 2 +- tests/functional/arrlabels6.asm | 2 +- tests/functional/arrlabels7.asm | 2 +- tests/functional/arrlabels8.asm | 2 +- tests/functional/arrlabels9.asm | 2 +- tests/functional/astore16.asm | 792 ++++++------ tests/functional/ataddr.asm | 2 +- tests/functional/atfunc0.asm | 2 +- tests/functional/atfunc1.asm | 2 +- tests/functional/atlabel.asm | 2 +- tests/functional/atlabel1.asm | 10 +- tests/functional/atlabel2.asm | 2 +- tests/functional/atlabel3.asm | 2 +- tests/functional/attr.asm | 138 +- tests/functional/band16.asm | 16 +- tests/functional/band32.asm | 24 +- tests/functional/band8.asm | 10 +- tests/functional/bin00.asm | 2 +- tests/functional/bitwise.asm | 10 +- tests/functional/bnot16.asm | 16 +- tests/functional/bor16.asm | 14 +- tests/functional/bor32.asm | 24 +- tests/functional/bor8.asm | 2 +- tests/functional/bound00.asm | 2 +- tests/functional/bound01.asm | 2 +- tests/functional/bound02.asm | 18 +- tests/functional/bound03.asm | 18 +- tests/functional/bound04.asm | 2 +- tests/functional/britlion0.asm | 2 +- tests/functional/bxor16.asm | 20 +- tests/functional/bxor32.asm | 24 +- tests/functional/bxor8.asm | 2 +- tests/functional/byref32.asm | 22 +- tests/functional/byte_neq.asm | 2 +- tests/functional/byval32.asm | 14 +- tests/functional/castF16toF.asm | 108 +- tests/functional/chr.asm | 462 +++---- tests/functional/chr0.asm | 316 ++--- tests/functional/chr1.asm | 394 +++--- tests/functional/circle.asm | 298 ++--- tests/functional/code00.asm | 914 +++++++------- tests/functional/code01.asm | 914 +++++++------- tests/functional/code02.asm | 914 +++++++------- tests/functional/codecrash1.asm | 174 +-- tests/functional/codecrash2.asm | 360 +++--- tests/functional/codecrash3.asm | 304 ++--- tests/functional/codecrash4.asm | 394 +++--- tests/functional/coercion1.asm | 214 ++-- tests/functional/coercion3.asm | 64 +- tests/functional/const0.asm | 2 +- tests/functional/const1.asm | 2 +- tests/functional/const3.asm | 2 +- tests/functional/cpeq16.asm | 6 +- tests/functional/declare0.asm | 2 +- tests/functional/defb.asm | 2 +- tests/functional/dimconst.asm | 2 +- tests/functional/dimconst2.asm | 2 +- tests/functional/dimconst2c.asm | 2 +- tests/functional/dimconst2d.asm | 2 +- tests/functional/dimconst2e.asm | 2 +- tests/functional/dimconst3.asm | 2 +- tests/functional/dimconst4.asm | 2 +- tests/functional/dimconst4b.asm | 2 +- tests/functional/dimconst4c.asm | 2 +- tests/functional/dimconst5.asm | 2 +- tests/functional/dimconst6.asm | 2 +- tests/functional/div32.asm | 156 +-- tests/functional/divf00.asm | 94 +- tests/functional/divf01.asm | 82 +- tests/functional/divf16.asm | 254 ++-- tests/functional/divf16a.asm | 254 ++-- tests/functional/divf16b.asm | 254 ++-- tests/functional/divf16c.asm | 260 ++-- tests/functional/divi16a.asm | 72 +- tests/functional/divi16b.asm | 72 +- tests/functional/divi32c.asm | 94 +- tests/functional/divi8.asm | 74 +- tests/functional/divi8a.asm | 74 +- tests/functional/divi8b.asm | 74 +- tests/functional/divu16.asm | 72 +- tests/functional/divu16a.asm | 72 +- tests/functional/divu16b.asm | 72 +- tests/functional/divu32c.asm | 94 +- tests/functional/divu8.asm | 74 +- tests/functional/divu8a.asm | 74 +- tests/functional/divu8b.asm | 74 +- tests/functional/dollar.asm | 2 +- tests/functional/doloop.asm | 2 +- tests/functional/doloop1.asm | 2 +- tests/functional/doloop2.asm | 2 +- tests/functional/doloop3.asm | 2 +- tests/functional/dountil1.asm | 2 +- tests/functional/dowhile1.asm | 2 +- tests/functional/draw.asm | 606 ++++----- tests/functional/draw3.asm | 996 +++++++-------- tests/functional/einar01.asm | 2 +- tests/functional/einarattr.asm | 748 +++++------ tests/functional/einarshift.asm | 688 +++++----- tests/functional/elseif.asm | 2 +- tests/functional/elseif1.asm | 2 +- tests/functional/elseif2.asm | 2 +- tests/functional/elseif3.asm | 10 +- tests/functional/elseif4.asm | 2 +- tests/functional/elseif5.asm | 10 +- tests/functional/elseif6.asm | 10 +- tests/functional/emptystrparam.asm | 270 ++-- tests/functional/end.asm | 2 +- tests/functional/eq0.asm | 168 +-- tests/functional/equ8.asm | 2 +- tests/functional/fastcall0.asm | 422 +++---- tests/functional/for0.asm | 876 ++++++------- tests/functional/fornext.asm | 2 +- tests/functional/fornext2.asm | 2 +- tests/functional/fornext3.asm | 2 +- tests/functional/fporder.asm | 86 +- tests/functional/funccall0.asm | 2 +- tests/functional/funccall1.asm | 2 +- tests/functional/funccall2.asm | 2 +- tests/functional/funcnoparm.asm | 2 +- tests/functional/gef16.asm | 32 +- tests/functional/gei32.asm | 32 +- tests/functional/gei8.asm | 8 +- tests/functional/geu32.asm | 20 +- tests/functional/gtf16.asm | 34 +- tests/functional/gti32.asm | 34 +- tests/functional/gti8.asm | 10 +- tests/functional/gtu32.asm | 8 +- tests/functional/gtu8.asm | 2 +- tests/functional/idco.asm | 2 +- tests/functional/ifelse0.asm | 2 +- tests/functional/ifelse1.asm | 744 +++++------ tests/functional/ifthen.asm | 10 +- tests/functional/ifthenelse.asm | 10 +- tests/functional/ifthenelseif.asm | 10 +- tests/functional/in0.asm | 2 +- tests/functional/inkey.asm | 884 ++++++------- tests/functional/inktemp.asm | 810 ++++++------ tests/functional/lcd3.asm | 1176 ++++++++--------- tests/functional/lcd5.asm | 2 +- tests/functional/lcd6.asm | 2 +- tests/functional/lcd7.asm | 1006 +++++++-------- tests/functional/lcd8.asm | 850 ++++++------- tests/functional/lcd9.asm | 996 +++++++-------- tests/functional/lef16.asm | 34 +- tests/functional/lei32.asm | 34 +- tests/functional/let0.asm | 2 +- tests/functional/leu32.asm | 8 +- tests/functional/load02.asm | 914 +++++++------- tests/functional/load03.asm | 914 +++++++------- tests/functional/loadstr.asm | 554 ++++----- tests/functional/loadu16ii.asm | 714 +++++------ tests/functional/localdim.asm | 2 +- tests/functional/ltee1.asm | 1128 ++++++++--------- tests/functional/ltee10.asm | 104 +- tests/functional/ltee3.asm | 270 ++-- tests/functional/ltee4.asm | 2 +- tests/functional/ltee5.asm | 408 +++--- tests/functional/ltee6.asm | 496 ++++---- tests/functional/ltee7.asm | 540 ++++---- tests/functional/ltee8.asm | 2 +- tests/functional/ltee9.asm | 132 +- tests/functional/ltf16.asm | 32 +- tests/functional/lti32c.asm | 32 +- tests/functional/ltu32c.asm | 20 +- tests/functional/mcleod.asm | 148 +-- tests/functional/mcleod2.asm | 394 +++--- tests/functional/modf16.asm | 2 +- tests/functional/modf16c.asm | 340 ++--- tests/functional/modi32c.asm | 94 +- tests/functional/modi8.asm | 74 +- tests/functional/modi8a.asm | 74 +- tests/functional/modi8b.asm | 74 +- tests/functional/modu32c.asm | 94 +- tests/functional/modu8.asm | 74 +- tests/functional/modu8a.asm | 74 +- tests/functional/modu8b.asm | 74 +- tests/functional/mul16.asm | 26 +- tests/functional/mul16a.asm | 26 +- tests/functional/mul16b.asm | 26 +- tests/functional/mul8.asm | 24 +- tests/functional/mul8a.asm | 24 +- tests/functional/mul8b.asm | 24 +- tests/functional/mulf00.asm | 56 +- tests/functional/mulf01.asm | 44 +- tests/functional/mulf16a.asm | 74 +- tests/functional/nir.asm | 2 +- tests/functional/octal.asm | 2 +- tests/functional/ongoto.asm | 752 +++++------ tests/functional/opt2_ifbyte.asm | 2 +- tests/functional/opt2_labelinfunc.asm | 2 +- tests/functional/opt2_labelinfunc3.asm | 2 +- tests/functional/opt2_labelinfunc4.asm | 2 +- tests/functional/opt2_labelinfunc5.asm | 2 +- tests/functional/opt2_localu8.asm | 2 +- tests/functional/opt2_pstr.asm | 270 ++-- tests/functional/opt3_17.asm | 2 +- tests/functional/opt3_asmexpr.asm | 2 +- tests/functional/opt3_atolo1.asm | 2 +- tests/functional/opt3_atolo4.asm | 2 +- tests/functional/opt3_atoloinc.asm | 2 +- tests/functional/opt3_dark01.asm | 2 +- tests/functional/opt3_einar.asm | 744 +++++------ tests/functional/opt3_einar04.asm | 2 +- tests/functional/opt3_einar05.asm | 2 +- tests/functional/opt3_einar06.asm | 2 +- tests/functional/opt3_haplo01.asm | 2 +- tests/functional/opt3_lcd5.asm | 90 +- tests/functional/opt3_lcd6.asm | 2 +- tests/functional/opt3_ldhlhl.asm | 2 +- tests/functional/opt3_proc0.asm | 2 +- tests/functional/opt3_sp.asm | 160 +-- tests/functional/optconst.asm | 710 +++++------ tests/functional/or16.asm | 2 +- tests/functional/or32.asm | 22 +- tests/functional/or8.asm | 2 +- tests/functional/out0.asm | 70 +- tests/functional/param0.asm | 932 +++++++------- tests/functional/param1.asm | 974 +++++++-------- tests/functional/param2.asm | 932 +++++++------- tests/functional/parambyref1.asm | 690 +++++----- tests/functional/paramint3.asm | 2 +- tests/functional/paramstr3.asm | 270 ++-- tests/functional/paramstr4.asm | 270 ++-- tests/functional/paramstr5.asm | 270 ++-- tests/functional/plot.asm | 198 +-- tests/functional/poke0.asm | 2 +- tests/functional/poke1.asm | 2 +- tests/functional/poke2.asm | 2 +- tests/functional/pokeref.asm | 2 +- tests/functional/pokeref1.asm | 2 +- tests/functional/pokeref2.asm | 2 +- tests/functional/pooky0.asm | 152 +-- tests/functional/print.asm | 1264 +++++++++---------- tests/functional/print42.asm | 154 +-- tests/functional/print64.asm | 154 +-- tests/functional/randomize.asm | 46 +- tests/functional/read.asm | 588 ++++----- tests/functional/read10.asm | 1290 +++++++++---------- tests/functional/read12.asm | 1242 +++++++++--------- tests/functional/read4.asm | 678 +++++----- tests/functional/read5.asm | 1270 +++++++++---------- tests/functional/read8.asm | 1270 +++++++++---------- tests/functional/read9.asm | 1374 ++++++++++---------- tests/functional/readokdown.asm | 1592 ++++++++++++------------ tests/functional/readokup.asm | 1592 ++++++++++++------------ tests/functional/recur0.asm | 2 +- tests/functional/refconstparam.asm | 2 +- tests/functional/refconstparam2.asm | 2 +- tests/functional/refconstparam4.asm | 2 +- tests/functional/refconstparam5.asm | 2 +- tests/functional/refconstparam6.asm | 2 +- tests/functional/save01.asm | 230 ++-- tests/functional/save02.asm | 230 ++-- tests/functional/save03.asm | 230 ++-- tests/functional/sgnf.asm | 24 +- tests/functional/sgnf16.asm | 24 +- tests/functional/sgni16.asm | 24 +- tests/functional/sgni32.asm | 24 +- tests/functional/sgni8.asm | 8 +- tests/functional/sgnu16.asm | 8 +- tests/functional/sgnu32.asm | 10 +- tests/functional/sgnu8.asm | 8 +- tests/functional/shl8.asm | 2 +- tests/functional/shri8.asm | 2 +- tests/functional/shru8.asm | 2 +- tests/functional/sigilfunc.asm | 288 ++--- tests/functional/simple.asm | 744 +++++------ tests/functional/slice0.asm | 338 ++--- tests/functional/slice2.asm | 420 +++---- tests/functional/spfill.asm | 422 +++---- tests/functional/stoperr.asm | 24 +- tests/functional/storecstr.asm | 394 +++--- tests/functional/storef.asm | 10 +- tests/functional/storestr0.asm | 394 +++--- tests/functional/storestr1.asm | 406 +++--- tests/functional/storestr2.asm | 426 +++---- tests/functional/storeu16.asm | 2 +- tests/functional/storeu32.asm | 2 +- tests/functional/storeu8.asm | 2 +- tests/functional/str0.asm | 1054 ++++++++-------- tests/functional/str00.asm | 394 +++--- tests/functional/str01.asm | 406 +++--- tests/functional/str02.asm | 498 ++++---- tests/functional/stradd.asm | 504 ++++---- tests/functional/strbase.asm | 592 ++++----- tests/functional/strbase2.asm | 1172 ++++++++--------- tests/functional/strict2.asm | 2 +- tests/functional/stringfunc.asm | 270 ++-- tests/functional/stringparam.asm | 850 ++++++------- tests/functional/strlocal0.asm | 986 +++++++-------- tests/functional/strparam0.asm | 850 ++++++------- tests/functional/strparam1.asm | 636 +++++----- tests/functional/strparam2.asm | 974 +++++++-------- tests/functional/strparam3.asm | 850 ++++++------- tests/functional/strsigil.asm | 408 +++--- tests/functional/sub16.asm | 2 +- tests/functional/sub16a.asm | 2 +- tests/functional/sub16b.asm | 2 +- tests/functional/sub8.asm | 2 +- tests/functional/sub8a.asm | 2 +- tests/functional/sub8b.asm | 2 +- tests/functional/subf00.asm | 58 +- tests/functional/subf01.asm | 46 +- tests/functional/subf16c.asm | 20 +- tests/functional/subi32c.asm | 20 +- tests/functional/subparam.asm | 2 +- tests/functional/substrlval.asm | 502 ++++---- tests/functional/subu32c.asm | 20 +- tests/functional/usr0.asm | 872 ++++++------- tests/functional/valcrash2.asm | 464 +++---- tests/functional/while.asm | 166 +-- tests/functional/xor16.asm | 20 +- tests/functional/xor32.asm | 26 +- tests/functional/xor8.asm | 16 +- zxb.py | 5 +- 415 files changed, 37207 insertions(+), 37206 deletions(-) diff --git a/tests/functional/00.asm b/tests/functional/00.asm index a67a88f09..6323e744f 100644 --- a/tests/functional/00.asm +++ b/tests/functional/00.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00, 00 diff --git a/tests/functional/02.asm b/tests/functional/02.asm index 460452dd8..e52d2a3ae 100644 --- a/tests/functional/02.asm +++ b/tests/functional/02.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/03.asm b/tests/functional/03.asm index 225aebe3f..237c470ee 100644 --- a/tests/functional/03.asm +++ b/tests/functional/03.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/04.asm b/tests/functional/04.asm index 460452dd8..e52d2a3ae 100644 --- a/tests/functional/04.asm +++ b/tests/functional/04.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/05.asm b/tests/functional/05.asm index d1748f559..67c1a812d 100644 --- a/tests/functional/05.asm +++ b/tests/functional/05.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFW 0000h diff --git a/tests/functional/06.asm b/tests/functional/06.asm index 1e14a3494..d0cc043be 100644 --- a/tests/functional/06.asm +++ b/tests/functional/06.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFW 0000h diff --git a/tests/functional/07.asm b/tests/functional/07.asm index 05cdd2dd1..2669cd7fc 100644 --- a/tests/functional/07.asm +++ b/tests/functional/07.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFW 0001h diff --git a/tests/functional/08.asm b/tests/functional/08.asm index ddd57e805..118ef5cd6 100644 --- a/tests/functional/08.asm +++ b/tests/functional/08.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _x: DEFB 05h diff --git a/tests/functional/09.asm b/tests/functional/09.asm index c3e25833e..3b2ea1095 100644 --- a/tests/functional/09.asm +++ b/tests/functional/09.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFW 0000h diff --git a/tests/functional/10.asm b/tests/functional/10.asm index 4dd980305..bb2b17453 100644 --- a/tests/functional/10.asm +++ b/tests/functional/10.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFW 0000h diff --git a/tests/functional/11.asm b/tests/functional/11.asm index 18b2ced1c..9646a0511 100644 --- a/tests/functional/11.asm +++ b/tests/functional/11.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFW 0001h diff --git a/tests/functional/12.asm b/tests/functional/12.asm index f6cde66f8..5b057e94c 100644 --- a/tests/functional/12.asm +++ b/tests/functional/12.asm @@ -27,7 +27,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/13.asm b/tests/functional/13.asm index dd0e03770..d1021a9c6 100644 --- a/tests/functional/13.asm +++ b/tests/functional/13.asm @@ -27,7 +27,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/15.asm b/tests/functional/15.asm index 88083b6f3..cc027e745 100644 --- a/tests/functional/15.asm +++ b/tests/functional/15.asm @@ -30,7 +30,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/16.asm b/tests/functional/16.asm index a30afc56e..1f6d4b612 100644 --- a/tests/functional/16.asm +++ b/tests/functional/16.asm @@ -30,7 +30,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/17.asm b/tests/functional/17.asm index fe2b335e5..da6c72adb 100644 --- a/tests/functional/17.asm +++ b/tests/functional/17.asm @@ -31,7 +31,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/18.asm b/tests/functional/18.asm index 795a9995c..fae65d062 100644 --- a/tests/functional/18.asm +++ b/tests/functional/18.asm @@ -33,7 +33,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/19.asm b/tests/functional/19.asm index d6a117d4a..daceb35b0 100644 --- a/tests/functional/19.asm +++ b/tests/functional/19.asm @@ -81,40 +81,40 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "acos.asm" - + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -130,117 +130,117 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 2 "acos.asm" - + ACOS: ; Computes ACOS using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 23h ; ACOS defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 72 "19.bas" #line 1 "asin.asm" - - - + + + ASIN: ; Computes ASIN using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 22h ; ASIN defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 73 "19.bas" #line 1 "atan.asm" - - - + + + ATAN: ; Computes ATAN using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 24h ; ATAN defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 74 "19.bas" #line 1 "cos.asm" - - - + + + COS: ; Computes COS using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 20h ; COS defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 75 "19.bas" #line 1 "exp.asm" - - - + + + EXP: ; Computes e^n using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 26h ; E^n defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 76 "19.bas" #line 1 "logn.asm" - - - + + + LN: ; Computes Ln(x) using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 20h ; 25h defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 77 "19.bas" #line 1 "sin.asm" - - - + + + SIN: ; Computes SIN using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 1Fh defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 78 "19.bas" #line 1 "sqrt.asm" - - - + + + SQRT: ; Computes SQRT(x) using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 28h ; SQRT defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 79 "19.bas" #line 1 "storef.asm" - + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -248,7 +248,7 @@ __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory pop hl ; HL <- IX add hl, de ; HL <- IX + HL pop de - + __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register ex af, af' ld a, (hl) @@ -256,7 +256,7 @@ __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address ld h, (hl) ld l, a ; HL = (HL) ex af, af' - + __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), a inc hl @@ -268,23 +268,23 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL inc hl ld (hl), b ret - + #line 80 "19.bas" #line 1 "tan.asm" - - - + + + TAN: ; Computes TAN using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 21h ; TAN defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 81 "19.bas" - + ZXBASIC_USER_DATA: _x: DEFB 00, 00, 00, 00, 00 diff --git a/tests/functional/20.asm b/tests/functional/20.asm index c29f9c95f..b212e0033 100644 --- a/tests/functional/20.asm +++ b/tests/functional/20.asm @@ -28,7 +28,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/21.asm b/tests/functional/21.asm index ca4e0df84..6d44fc5a7 100644 --- a/tests/functional/21.asm +++ b/tests/functional/21.asm @@ -32,7 +32,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "storef.asm" - + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -40,7 +40,7 @@ __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory pop hl ; HL <- IX add hl, de ; HL <- IX + HL pop de - + __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register ex af, af' ld a, (hl) @@ -48,7 +48,7 @@ __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address ld h, (hl) ld l, a ; HL = (HL) ex af, af' - + __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), a inc hl @@ -60,9 +60,9 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL inc hl ld (hl), b ret - + #line 23 "21.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00, 00 diff --git a/tests/functional/22.asm b/tests/functional/22.asm index b1fd0c6f3..aaf00590f 100644 --- a/tests/functional/22.asm +++ b/tests/functional/22.asm @@ -29,7 +29,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _b: DEFB 00 diff --git a/tests/functional/25.asm b/tests/functional/25.asm index 9541c9092..a2b7a4386 100644 --- a/tests/functional/25.asm +++ b/tests/functional/25.asm @@ -35,12 +35,12 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "not32.asm" - + ; ------------------------------------------------------------- ; 32 bit logical NOT ; ------------------------------------------------------------- - -__NOT32: ; A = ¬A + +__NOT32: ; A = ¬A ld a, d or e or h @@ -48,10 +48,10 @@ __NOT32: ; A = ¬A sub 1 ; Gives CARRY only if 0 sbc a, a; Gives 0 if not carry, FF otherwise ret - - + + #line 26 "25.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00 diff --git a/tests/functional/26.asm b/tests/functional/26.asm index e7abd3ade..9f17ad2e3 100644 --- a/tests/functional/26.asm +++ b/tests/functional/26.asm @@ -28,7 +28,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/27.asm b/tests/functional/27.asm index c93e73b0b..21af47d39 100644 --- a/tests/functional/27.asm +++ b/tests/functional/27.asm @@ -42,7 +42,7 @@ __LABEL0: DEFB 49h DEFB 43h #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -53,15 +53,15 @@ __LABEL0: ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -69,25 +69,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -96,52 +96,52 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -149,12 +149,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -162,7 +162,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -170,10 +170,10 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -181,25 +181,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -208,42 +208,42 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -251,25 +251,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -278,39 +278,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -318,57 +318,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -380,27 +380,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -412,7 +412,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -420,15 +420,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -453,14 +453,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -468,25 +468,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 71 "realloc.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -494,25 +494,25 @@ __MEM_SUBTRACT: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -521,38 +521,38 @@ __MEM_SUBTRACT: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -561,57 +561,57 @@ __MEM_SUBTRACT: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -620,47 +620,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -670,12 +670,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 72 "realloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -694,29 +694,29 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -725,111 +725,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -845,7 +845,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -853,44 +853,44 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 30 "27.bas" - + ZXBASIC_USER_DATA: _b: DEFB 00, 00 diff --git a/tests/functional/28.asm b/tests/functional/28.asm index 0b1d7089c..4c6be573c 100644 --- a/tests/functional/28.asm +++ b/tests/functional/28.asm @@ -45,7 +45,7 @@ __LABEL0: DEFB 49h DEFB 43h #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -56,15 +56,15 @@ __LABEL0: ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -72,25 +72,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -99,52 +99,52 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -152,12 +152,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -165,7 +165,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -173,10 +173,10 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -184,25 +184,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -211,42 +211,42 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -254,25 +254,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -281,39 +281,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -321,57 +321,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -383,27 +383,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -415,7 +415,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -423,15 +423,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -456,14 +456,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -471,25 +471,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 71 "realloc.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -497,25 +497,25 @@ __MEM_SUBTRACT: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -524,38 +524,38 @@ __MEM_SUBTRACT: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -564,57 +564,57 @@ __MEM_SUBTRACT: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -623,47 +623,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -673,12 +673,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 72 "realloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -697,29 +697,29 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -728,111 +728,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -848,7 +848,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -856,63 +856,63 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 33 "28.bas" #line 1 "strlen.asm" - + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL - + __STRLEN: ; Direct FASTCALL entry ld a, h or l ret z - + ld a, (hl) inc hl ld h, (hl) ; LEN(str) in HL ld l, a ret - - + + #line 34 "28.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/29.asm b/tests/functional/29.asm index 90027a708..83214e146 100644 --- a/tests/functional/29.asm +++ b/tests/functional/29.asm @@ -51,10 +51,10 @@ __LABEL0: DEFB 49h DEFB 43h #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -62,25 +62,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -89,51 +89,51 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -141,12 +141,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -154,7 +154,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -162,10 +162,10 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -173,25 +173,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -200,39 +200,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -240,57 +240,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -302,27 +302,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -334,7 +334,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -342,15 +342,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -375,14 +375,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -390,22 +390,22 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 39 "29.bas" #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -416,15 +416,15 @@ __MEM_SUBTRACT: ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -432,25 +432,25 @@ __MEM_SUBTRACT: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -459,44 +459,44 @@ __MEM_SUBTRACT: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -504,25 +504,25 @@ __MEM_SUBTRACT: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -531,38 +531,38 @@ __MEM_SUBTRACT: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -571,57 +571,57 @@ __MEM_SUBTRACT: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -630,47 +630,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -680,12 +680,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 72 "realloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -704,29 +704,29 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -735,111 +735,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -855,7 +855,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -863,140 +863,140 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 40 "29.bas" #line 1 "strcat.asm" - - + + #line 1 "strlen.asm" - + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL - + __STRLEN: ; Direct FASTCALL entry ld a, h or l ret z - + ld a, (hl) inc hl ld h, (hl) ; LEN(str) in HL ld l, a ret - - + + #line 3 "strcat.asm" - + __ADDSTR: ; Implements c$ = a$ + b$ ; hl = &a$, de = &b$ (pointers) - - + + __STRCAT2: ; This routine creates a new string in dynamic space ; making room for it. Then copies a$ + b$ into it. ; HL = a$, DE = b$ - + PROC - + LOCAL __STR_CONT LOCAL __STRCATEND - + push hl call __STRLEN ld c, l ld b, h ; BC = LEN(a$) ex (sp), hl ; (SP) = LEN (a$), HL = a$ push hl ; Saves pointer to a$ - + inc bc inc bc ; +2 bytes to store length - + ex de, hl push hl call __STRLEN ; HL = len(b$) - + add hl, bc ; Total str length => 2 + len(a$) + len(b$) - + ld c, l ld b, h ; BC = Total str length + 2 - call __MEM_ALLOC - pop de ; HL = c$, DE = b$ - + call __MEM_ALLOC + pop de ; HL = c$, DE = b$ + ex de, hl ; HL = b$, DE = c$ - ex (sp), hl ; HL = a$, (SP) = b$ - + ex (sp), hl ; HL = a$, (SP) = b$ + exx - pop de ; D'E' = b$ + pop de ; D'E' = b$ exx - + pop bc ; LEN(a$) - + ld a, d or e ret z ; If no memory: RETURN - + __STR_CONT: push de ; Address of c$ - + ld a, h or l jr nz, __STR_CONT1 ; If len(a$) != 0 do copy - + ; a$ is NULL => uses HL = DE for transfer ld h, d ld l, e ld (hl), a ; This will copy 00 00 at (DE) location - inc de ; + inc de ; dec bc ; Ensure BC will be set to 1 in the next step - + __STR_CONT1: ; Copies a$ (HL) into c$ (DE) - inc bc + inc bc inc bc ; BC = BC + 2 ldir ; MEMCOPY: c$ = a$ pop hl ; HL = c$ - + exx push de ; Recovers b$; A ex hl,hl' would be very handy exx - - pop de ; DE = b$ - + + pop de ; DE = b$ + __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ; NOTE: Both DE, BC and AF are modified and lost ; Returns HL (pointer to a$) @@ -1004,51 +1004,51 @@ __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ld a, d or e ret z ; Returns if de is NULL (nothing to copy) - + push hl ; Saves HL to return it later - + ld c, (hl) inc hl ld b, (hl) inc hl add hl, bc ; HL = end of (a$) string ; bc = len(a$) push bc ; Saves LEN(a$) for later - + ex de, hl ; DE = end of string (Begin of copy addr) ld c, (hl) inc hl ld b, (hl) ; BC = len(b$) - + ld a, b or c jr z, __STRCATEND; Return if len(b$) == 0 - + push bc ; Save LEN(b$) inc hl ; Skip 2nd byte of len(b$) ldir ; Concatenate b$ - + pop bc ; Recovers length (b$) pop hl ; Recovers length (a$) add hl, bc ; HL = LEN(a$) + LEN(b$) = LEN(a$+b$) ex de, hl ; DE = LEN(a$+b$) pop hl - + ld (hl), e ; Updates new LEN and return inc hl ld (hl), d dec hl ret - + __STRCATEND: pop hl ; Removes Len(a$) pop hl ; Restores original HL, so HL = a$ ret - + ENDP - + #line 41 "29.bas" - - + + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/30.asm b/tests/functional/30.asm index ae456c69c..29d470df1 100644 --- a/tests/functional/30.asm +++ b/tests/functional/30.asm @@ -34,7 +34,7 @@ _a__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/31.asm b/tests/functional/31.asm index 6d8864ba7..79d791678 100644 --- a/tests/functional/31.asm +++ b/tests/functional/31.asm @@ -43,40 +43,40 @@ _test__leave: pop ix ret #line 1 "addf.asm" - + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -92,7 +92,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 2 "addf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) ; All of them uses A EDCB registers as 1st paramter. @@ -101,26 +101,26 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; ; Uses CALLEE convention ; ------------------------------------------------------------- - + __ADDF: ; Addition call __FPSTACK_PUSH2 - + ; ------------- ROM ADD rst 28h defb 0fh ; ADD defb 38h; ; END CALC - + jp __FPSTACK_POP - + #line 34 "31.bas" #line 1 "pushf.asm" - - - ; Routine to push Float pointed by HL + + + ; Routine to push Float pointed by HL ; Into the stack. Notice that the hl points to the last ; byte of the FP number. ; Uses H'L' B'C' and D'E' to preserve ABCDEHL registers - + __FP_PUSH_REV: push hl exx @@ -141,11 +141,11 @@ __FP_PUSH_REV: push bc ; Return Address exx ret - - + + #line 35 "31.bas" #line 1 "storef.asm" - + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -153,7 +153,7 @@ __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory pop hl ; HL <- IX add hl, de ; HL <- IX + HL pop de - + __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register ex af, af' ld a, (hl) @@ -161,7 +161,7 @@ __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address ld h, (hl) ld l, a ; HL = (HL) ex af, af' - + __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), a inc hl @@ -173,9 +173,9 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL inc hl ld (hl), b ret - + #line 36 "31.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00, 00 diff --git a/tests/functional/32.asm b/tests/functional/32.asm index 463b933d7..d0923cdbf 100644 --- a/tests/functional/32.asm +++ b/tests/functional/32.asm @@ -41,7 +41,7 @@ _test__leave: ex (sp), hl exx ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/33.asm b/tests/functional/33.asm index a74120f96..47677cee4 100644 --- a/tests/functional/33.asm +++ b/tests/functional/33.asm @@ -41,7 +41,7 @@ _test__leave: ex (sp), hl exx ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/34.asm b/tests/functional/34.asm index e0310dbd8..4dc3da3e9 100644 --- a/tests/functional/34.asm +++ b/tests/functional/34.asm @@ -42,39 +42,39 @@ _test__leave: exx ret #line 1 "u32tofreg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "u32tofreg.asm" __I8TOFREG: ld l, a @@ -83,35 +83,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -119,20 +119,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -140,32 +140,32 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 33 "34.bas" - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/35.asm b/tests/functional/35.asm index ae5271d4c..8be3086e9 100644 --- a/tests/functional/35.asm +++ b/tests/functional/35.asm @@ -55,40 +55,40 @@ _test__leave: exx ret #line 1 "addf.asm" - + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -104,7 +104,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 2 "addf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) ; All of them uses A EDCB registers as 1st paramter. @@ -113,45 +113,45 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; ; Uses CALLEE convention ; ------------------------------------------------------------- - + __ADDF: ; Addition call __FPSTACK_PUSH2 - + ; ------------- ROM ADD rst 28h defb 0fh ; ADD defb 38h; ; END CALC - + jp __FPSTACK_POP - + #line 46 "35.bas" #line 1 "ploadf.asm" - + ; Parameter / Local var load ; A => Offset ; IX = Stack Frame ; RESULT: HL => IX + DE - + #line 1 "iloadf.asm" - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- ((HL)) - + __ILOADF: ld a, (hl) inc hl ld h, (hl) ld l, a - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- (HL) - + __LOADF: ; Loads a 40 bits FP number from address pointed by HL - ld a, (hl) + ld a, (hl) inc hl ld e, (hl) inc hl @@ -161,50 +161,50 @@ __LOADF: ; Loads a 40 bits FP number from address pointed by HL inc hl ld b, (hl) ret - + #line 7 "ploadf.asm" - + __PLOADF: push ix pop hl add hl, de jp __LOADF - + #line 47 "35.bas" #line 1 "u32tofreg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "u32tofreg.asm" __I8TOFREG: ld l, a @@ -213,35 +213,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -249,20 +249,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -270,32 +270,32 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 48 "35.bas" - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/36.asm b/tests/functional/36.asm index 1755b1c51..d4e9131f1 100644 --- a/tests/functional/36.asm +++ b/tests/functional/36.asm @@ -58,40 +58,40 @@ _test__leave: exx ret #line 1 "addf.asm" - + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -107,7 +107,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 2 "addf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) ; All of them uses A EDCB registers as 1st paramter. @@ -116,45 +116,45 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; ; Uses CALLEE convention ; ------------------------------------------------------------- - + __ADDF: ; Addition call __FPSTACK_PUSH2 - + ; ------------- ROM ADD rst 28h defb 0fh ; ADD defb 38h; ; END CALC - + jp __FPSTACK_POP - + #line 49 "36.bas" #line 1 "ploadf.asm" - + ; Parameter / Local var load ; A => Offset ; IX = Stack Frame ; RESULT: HL => IX + DE - + #line 1 "iloadf.asm" - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- ((HL)) - + __ILOADF: ld a, (hl) inc hl ld h, (hl) ld l, a - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- (HL) - + __LOADF: ; Loads a 40 bits FP number from address pointed by HL - ld a, (hl) + ld a, (hl) inc hl ld e, (hl) inc hl @@ -164,50 +164,50 @@ __LOADF: ; Loads a 40 bits FP number from address pointed by HL inc hl ld b, (hl) ret - + #line 7 "ploadf.asm" - + __PLOADF: push ix pop hl add hl, de jp __LOADF - + #line 50 "36.bas" #line 1 "u32tofreg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "u32tofreg.asm" __I8TOFREG: ld l, a @@ -216,35 +216,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -252,20 +252,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -273,32 +273,32 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 51 "36.bas" - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/37.asm b/tests/functional/37.asm index d68a43526..3f1825c5a 100644 --- a/tests/functional/37.asm +++ b/tests/functional/37.asm @@ -58,40 +58,40 @@ _test__leave: exx ret #line 1 "addf.asm" - + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -107,7 +107,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 2 "addf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) ; All of them uses A EDCB registers as 1st paramter. @@ -116,45 +116,45 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; ; Uses CALLEE convention ; ------------------------------------------------------------- - + __ADDF: ; Addition call __FPSTACK_PUSH2 - + ; ------------- ROM ADD rst 28h defb 0fh ; ADD defb 38h; ; END CALC - + jp __FPSTACK_POP - + #line 49 "37.bas" #line 1 "ploadf.asm" - + ; Parameter / Local var load ; A => Offset ; IX = Stack Frame ; RESULT: HL => IX + DE - + #line 1 "iloadf.asm" - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- ((HL)) - + __ILOADF: ld a, (hl) inc hl ld h, (hl) ld l, a - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- (HL) - + __LOADF: ; Loads a 40 bits FP number from address pointed by HL - ld a, (hl) + ld a, (hl) inc hl ld e, (hl) inc hl @@ -164,50 +164,50 @@ __LOADF: ; Loads a 40 bits FP number from address pointed by HL inc hl ld b, (hl) ret - + #line 7 "ploadf.asm" - + __PLOADF: push ix pop hl add hl, de jp __LOADF - + #line 50 "37.bas" #line 1 "u32tofreg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "u32tofreg.asm" __I8TOFREG: ld l, a @@ -216,35 +216,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -252,20 +252,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -273,32 +273,32 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 51 "37.bas" - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/38.asm b/tests/functional/38.asm index b20128e39..f20331a8b 100644 --- a/tests/functional/38.asm +++ b/tests/functional/38.asm @@ -58,40 +58,40 @@ _test__leave: exx ret #line 1 "addf.asm" - + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -107,7 +107,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 2 "addf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) ; All of them uses A EDCB registers as 1st paramter. @@ -116,45 +116,45 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; ; Uses CALLEE convention ; ------------------------------------------------------------- - + __ADDF: ; Addition call __FPSTACK_PUSH2 - + ; ------------- ROM ADD rst 28h defb 0fh ; ADD defb 38h; ; END CALC - + jp __FPSTACK_POP - + #line 49 "38.bas" #line 1 "ploadf.asm" - + ; Parameter / Local var load ; A => Offset ; IX = Stack Frame ; RESULT: HL => IX + DE - + #line 1 "iloadf.asm" - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- ((HL)) - + __ILOADF: ld a, (hl) inc hl ld h, (hl) ld l, a - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- (HL) - + __LOADF: ; Loads a 40 bits FP number from address pointed by HL - ld a, (hl) + ld a, (hl) inc hl ld e, (hl) inc hl @@ -164,50 +164,50 @@ __LOADF: ; Loads a 40 bits FP number from address pointed by HL inc hl ld b, (hl) ret - + #line 7 "ploadf.asm" - + __PLOADF: push ix pop hl add hl, de jp __LOADF - + #line 50 "38.bas" #line 1 "u32tofreg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "u32tofreg.asm" __I8TOFREG: ld l, a @@ -216,35 +216,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -252,20 +252,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -273,32 +273,32 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 51 "38.bas" - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/39.asm b/tests/functional/39.asm index 45bed186a..53108325f 100644 --- a/tests/functional/39.asm +++ b/tests/functional/39.asm @@ -60,39 +60,39 @@ _test__leave: exx ret #line 1 "u32tofreg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "u32tofreg.asm" __I8TOFREG: ld l, a @@ -101,35 +101,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -137,20 +137,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -158,32 +158,32 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 51 "39.bas" - + ZXBASIC_USER_DATA: __LABEL0: DEFB 02h diff --git a/tests/functional/40.asm b/tests/functional/40.asm index 01df4667e..6cdea066b 100644 --- a/tests/functional/40.asm +++ b/tests/functional/40.asm @@ -53,39 +53,39 @@ _test__leave: exx ret #line 1 "u32tofreg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "u32tofreg.asm" __I8TOFREG: ld l, a @@ -94,35 +94,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -130,20 +130,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -151,32 +151,32 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 44 "40.bas" - + ZXBASIC_USER_DATA: __LABEL0: DEFB 00h diff --git a/tests/functional/41.asm b/tests/functional/41.asm index f00ddf62f..8144a35a0 100644 --- a/tests/functional/41.asm +++ b/tests/functional/41.asm @@ -28,7 +28,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/42.asm b/tests/functional/42.asm index 8a023d07c..de8806de8 100644 --- a/tests/functional/42.asm +++ b/tests/functional/42.asm @@ -52,7 +52,7 @@ _test__leave: ex (sp), hl exx ret - + ZXBASIC_USER_DATA: __LABEL0: DEFB 00h diff --git a/tests/functional/43.asm b/tests/functional/43.asm index 8f1e3aa3c..667389118 100644 --- a/tests/functional/43.asm +++ b/tests/functional/43.asm @@ -58,39 +58,39 @@ _test__leave: exx ret #line 1 "u32tofreg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "u32tofreg.asm" __I8TOFREG: ld l, a @@ -99,35 +99,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -135,20 +135,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -156,32 +156,32 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 49 "43.bas" - + ZXBASIC_USER_DATA: __LABEL0: DEFB 00h diff --git a/tests/functional/44.asm b/tests/functional/44.asm index 13654a194..a08683df0 100644 --- a/tests/functional/44.asm +++ b/tests/functional/44.asm @@ -28,7 +28,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/45.asm b/tests/functional/45.asm index 9bf23a5ce..10b3ad26d 100644 --- a/tests/functional/45.asm +++ b/tests/functional/45.asm @@ -53,7 +53,7 @@ _test__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: __LABEL0: DEFB 01h diff --git a/tests/functional/46.asm b/tests/functional/46.asm index a1a15407e..ca025a8d4 100644 --- a/tests/functional/46.asm +++ b/tests/functional/46.asm @@ -42,10 +42,10 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "array.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ------------------------------------------------------------------- ; Simple array Index routine @@ -53,28 +53,28 @@ __CALL_BACK__: ; HL = Start of array memory (First two bytes contains N-1 dimensions) ; Dimension values on the stack, (top of the stack, highest dimension) ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> - + ; For any array of N dimension A(aN-1, ..., a1, a0) ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] ; What I will do here is to calculate the following sequence: ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... - - + + #line 1 "mul16.asm" - + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned - + PROC - + LOCAL __MUL16LOOP LOCAL __MUL16NOADD - + ex de, hl pop hl ; Return address ex (sp), hl ; CALLEE caller convention - + ;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand ;; ld c, h ;; ld a, l ; C,A => 1st Operand @@ -92,44 +92,44 @@ __MUL16: ; Mutiplies HL with the last value stored into de stack ;;__MUL16NOADD: ;; sla e ;; rl d - ;; + ;; ;; djnz __MUL16LOOP - + __MUL16_FAST: ld b, 16 ld a, d ld c, e ex de, hl ld hl, 0 - + __MUL16LOOP: add hl, hl ; hl << 1 sla c rla ; a,c << 1 jp nc, __MUL16NOADD add hl, de - + __MUL16NOADD: djnz __MUL16LOOP - + ret ; Result in hl (16 lower bits) - + ENDP - + #line 20 "array.asm" - + #line 24 "/src/zxb/trunk/library-asm/array.asm" - + __ARRAY: PROC - + LOCAL LOOP LOCAL ARRAY_END LOCAL RET_ADDRESS ; Stores return address - + ex (sp), hl ; Return address in HL, array address in the stack ld (RET_ADDRESS + 1), hl ; Stores it for later - + exx pop hl ; Will use H'L' as the pointer ld c, (hl) ; Loads Number of dimensions from (hl) @@ -137,23 +137,23 @@ __ARRAY: ld b, (hl) inc hl ; Ready exx - + ld hl, 0 ; BC = Offset "accumulator" - + #line 48 "/src/zxb/trunk/library-asm/array.asm" - + LOOP: pop bc ; Get next index (Ai) from the stack - + #line 60 "/src/zxb/trunk/library-asm/array.asm" - + add hl, bc ; Adds current index - + exx ; Checks if B'C' = 0 ld a, b ; Which means we must exit (last element is not multiplied by anything) or c jr z, ARRAY_END ; if B'Ci == 0 we are done - + ld e, (hl) ; Loads next dimension into D'E' inc hl ld d, (hl) @@ -162,13 +162,13 @@ LOOP: dec bc ; Decrements loop counter exx pop de ; DE = Max bound Number (i-th dimension) - + #line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL #line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP - + ARRAY_END: ld e, (hl) inc hl @@ -176,75 +176,75 @@ ARRAY_END: push hl push de exx - + #line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP - + ex de, hl ld hl, 0 pop bc ld b, c -ARRAY_SIZE_LOOP: +ARRAY_SIZE_LOOP: add hl, de djnz ARRAY_SIZE_LOOP - + ;; Even faster ;pop bc - + ;ld d, h ;ld e, l - + ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;dec c ;jp z, __ARRAY_FIN - + ;add hl, de - ;__ARRAY_FIN: + ;__ARRAY_FIN: #line 131 "/src/zxb/trunk/library-asm/array.asm" - + pop de add hl, de ; Adds element start - + RET_ADDRESS: ld de, 0 push de ret ; HL = (Start of Elements + Offset) - + ;; Performs a faster multiply for little 16bit numbs LOCAL __FNMUL, __FNMUL2 - + __FNMUL: xor a or d jp nz, __MUL16_FAST - + or e ex de, hl ret z - + cp 33 jp nc, __MUL16_FAST - + ld b, l ld l, h ; HL = 0 - + __FNMUL2: add hl, de djnz __FNMUL2 ret - + ENDP - + #line 33 "46.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/47.asm b/tests/functional/47.asm index 7dd550412..1f517ec29 100644 --- a/tests/functional/47.asm +++ b/tests/functional/47.asm @@ -69,10 +69,10 @@ _test__leave: pop ix ret #line 1 "array.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ------------------------------------------------------------------- ; Simple array Index routine @@ -80,28 +80,28 @@ _test__leave: ; HL = Start of array memory (First two bytes contains N-1 dimensions) ; Dimension values on the stack, (top of the stack, highest dimension) ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> - + ; For any array of N dimension A(aN-1, ..., a1, a0) ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] ; What I will do here is to calculate the following sequence: ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... - - + + #line 1 "mul16.asm" - + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned - + PROC - + LOCAL __MUL16LOOP LOCAL __MUL16NOADD - + ex de, hl pop hl ; Return address ex (sp), hl ; CALLEE caller convention - + ;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand ;; ld c, h ;; ld a, l ; C,A => 1st Operand @@ -119,44 +119,44 @@ __MUL16: ; Mutiplies HL with the last value stored into de stack ;;__MUL16NOADD: ;; sla e ;; rl d - ;; + ;; ;; djnz __MUL16LOOP - + __MUL16_FAST: ld b, 16 ld a, d ld c, e ex de, hl ld hl, 0 - + __MUL16LOOP: add hl, hl ; hl << 1 sla c rla ; a,c << 1 jp nc, __MUL16NOADD add hl, de - + __MUL16NOADD: djnz __MUL16LOOP - + ret ; Result in hl (16 lower bits) - + ENDP - + #line 20 "array.asm" - + #line 24 "/src/zxb/trunk/library-asm/array.asm" - + __ARRAY: PROC - + LOCAL LOOP LOCAL ARRAY_END LOCAL RET_ADDRESS ; Stores return address - + ex (sp), hl ; Return address in HL, array address in the stack ld (RET_ADDRESS + 1), hl ; Stores it for later - + exx pop hl ; Will use H'L' as the pointer ld c, (hl) ; Loads Number of dimensions from (hl) @@ -164,23 +164,23 @@ __ARRAY: ld b, (hl) inc hl ; Ready exx - + ld hl, 0 ; BC = Offset "accumulator" - + #line 48 "/src/zxb/trunk/library-asm/array.asm" - + LOOP: pop bc ; Get next index (Ai) from the stack - + #line 60 "/src/zxb/trunk/library-asm/array.asm" - + add hl, bc ; Adds current index - + exx ; Checks if B'C' = 0 ld a, b ; Which means we must exit (last element is not multiplied by anything) or c jr z, ARRAY_END ; if B'Ci == 0 we are done - + ld e, (hl) ; Loads next dimension into D'E' inc hl ld d, (hl) @@ -189,13 +189,13 @@ LOOP: dec bc ; Decrements loop counter exx pop de ; DE = Max bound Number (i-th dimension) - + #line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL #line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP - + ARRAY_END: ld e, (hl) inc hl @@ -203,75 +203,75 @@ ARRAY_END: push hl push de exx - + #line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP - + ex de, hl ld hl, 0 pop bc ld b, c -ARRAY_SIZE_LOOP: +ARRAY_SIZE_LOOP: add hl, de djnz ARRAY_SIZE_LOOP - + ;; Even faster ;pop bc - + ;ld d, h ;ld e, l - + ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;dec c ;jp z, __ARRAY_FIN - + ;add hl, de - ;__ARRAY_FIN: + ;__ARRAY_FIN: #line 131 "/src/zxb/trunk/library-asm/array.asm" - + pop de add hl, de ; Adds element start - + RET_ADDRESS: ld de, 0 push de ret ; HL = (Start of Elements + Offset) - + ;; Performs a faster multiply for little 16bit numbs LOCAL __FNMUL, __FNMUL2 - + __FNMUL: xor a or d jp nz, __MUL16_FAST - + or e ex de, hl ret z - + cp 33 jp nc, __MUL16_FAST - + ld b, l ld l, h ; HL = 0 - + __FNMUL2: add hl, de djnz __FNMUL2 ret - + ENDP - + #line 60 "47.bas" - + ZXBASIC_USER_DATA: __LABEL0: DEFB 01h diff --git a/tests/functional/48.asm b/tests/functional/48.asm index 66e72f0b7..c7b6b2d1a 100644 --- a/tests/functional/48.asm +++ b/tests/functional/48.asm @@ -53,7 +53,7 @@ __LABEL0: DEFB 49h DEFB 43h #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -64,15 +64,15 @@ __LABEL0: ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -80,25 +80,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -107,52 +107,52 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -160,12 +160,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -173,7 +173,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -181,10 +181,10 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -192,25 +192,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -219,42 +219,42 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -262,25 +262,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -289,39 +289,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -329,57 +329,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -391,27 +391,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -423,7 +423,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -431,15 +431,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -464,14 +464,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -479,25 +479,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 71 "realloc.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -505,25 +505,25 @@ __MEM_SUBTRACT: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -532,38 +532,38 @@ __MEM_SUBTRACT: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -572,57 +572,57 @@ __MEM_SUBTRACT: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -631,47 +631,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -681,12 +681,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 72 "realloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -705,29 +705,29 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -736,111 +736,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -856,7 +856,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -864,144 +864,144 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 41 "48.bas" #line 1 "storestr2.asm" - + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication ; HL = address of string memory variable ; DE = address of 2n string. It just copies DE into (HL) ; freeing (HL) previously. - - - + + + __PISTORE_STR2: ; Indirect store temporary string at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR2: ld c, (hl) ; Dereferences HL inc hl ld h, (hl) ld l, c ; HL = *HL (real string variable address) - + __STORE_STR2: push hl ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = *HL (real string address) - + push de call __MEM_FREE pop de - + pop hl ld (hl), e inc hl ld (hl), d dec hl ; HL points to mem address variable. This might be useful in the future. - + ret - + #line 42 "48.bas" #line 1 "strslice.asm" - + ; String slicing library ; HL = Str pointer ; DE = String start ; BC = String character end ; A register => 0 => the HL pointer wont' be freed from the HEAP ; e.g. a$(5 TO 10) => HL = a$; DE = 5; BC = 10 - - ; This implements a$(X to Y) being X and Y first and + + ; This implements a$(X to Y) being X and Y first and ; last characters respectively. If X > Y, NULL is returned - + ; Otherwise returns a pointer to a$ FROM X to Y (starting from 0) ; if Y > len(a$), then a$ will be padded with spaces (reallocating - ; it in dynamic memory if needed). Returns pointer (HL) to resulting + ; it in dynamic memory if needed). Returns pointer (HL) to resulting ; string. NULL (0) if no memory for padding. ; - + #line 1 "strlen.asm" - + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL - + __STRLEN: ; Direct FASTCALL entry ld a, h or l ret z - + ld a, (hl) inc hl ld h, (hl) ; LEN(str) in HL ld l, a ret - - + + #line 18 "strslice.asm" - - - + + + __STRSLICE: ; Callee entry pop hl ; Return ADDRESS pop bc ; Last char pos pop de ; 1st char pos ex (sp), hl ; CALLEE. -> String start - + __STRSLICE_FAST: ; __FASTCALL__ Entry PROC - + LOCAL __CONT LOCAL __EMPTY LOCAL __FREE_ON_EXIT - + push hl ; Stores original HL pointer to be recovered on exit ex af, af' ; Saves A register for later - + push hl call __STRLEN - inc bc ; Last character position + 1 (string starts from 0) + inc bc ; Last character position + 1 (string starts from 0) or a sbc hl, bc ; Compares length with last char position jr nc, __CONT ; If Carry => We must copy to end of string @@ -1009,19 +1009,19 @@ __STRSLICE_FAST: ; __FASTCALL__ Entry ld b, h ld c, l ; Copy to the end of str ccf ; Clears Carry flag for next subtraction - + __CONT: - ld h, b + ld h, b ld l, c ; HL = Last char position to copy (1 for char 0, 2 for char 1, etc) sbc hl, de ; HL = LEN(a$) - DE => Number of chars to copy jr z, __EMPTY ; 0 Chars to copy => Return HL = 0 (NULL STR) jr c, __EMPTY ; If Carry => Nothing to return (NULL STR) - + ld b, h ld c, l ; BC = Number of chars to copy inc bc inc bc ; +2 bytes for string length number - + push bc push de call __MEM_ALLOC @@ -1030,15 +1030,15 @@ __CONT: ld a, h or l jr z, __EMPTY ; Return if NULL (no memory) - + dec bc dec bc ; Number of chars to copy (Len of slice) - + ld (hl), c inc hl ld (hl), b inc hl ; Stores new string length - + ex (sp), hl ; Pointer to A$ now in HL; Pointer to new string chars in Stack inc hl inc hl ; Skip string length @@ -1051,26 +1051,26 @@ __CONT: dec de ; Points to String LEN start ex de, hl ; Returns it in HL jr __FREE_ON_EXIT - + __EMPTY: ; Return NULL (empty) string pop hl ld hl, 0 ; Return NULL - - + + __FREE_ON_EXIT: ex af, af' ; Recover original A register ex (sp), hl ; Original HL pointer - + or a call nz, __MEM_FREE - + pop hl ; Recover result - ret - - ENDP - + ret + + ENDP + #line 43 "48.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/49.asm b/tests/functional/49.asm index 6da77f964..aeca6373d 100644 --- a/tests/functional/49.asm +++ b/tests/functional/49.asm @@ -53,7 +53,7 @@ __LABEL0: DEFB 49h DEFB 43h #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -64,15 +64,15 @@ __LABEL0: ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -80,25 +80,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -107,52 +107,52 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -160,12 +160,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -173,7 +173,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -181,10 +181,10 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -192,25 +192,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -219,42 +219,42 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -262,25 +262,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -289,39 +289,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -329,57 +329,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -391,27 +391,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -423,7 +423,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -431,15 +431,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -464,14 +464,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -479,25 +479,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 71 "realloc.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -505,25 +505,25 @@ __MEM_SUBTRACT: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -532,38 +532,38 @@ __MEM_SUBTRACT: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -572,57 +572,57 @@ __MEM_SUBTRACT: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -631,47 +631,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -681,12 +681,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 72 "realloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -705,29 +705,29 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -736,111 +736,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -856,7 +856,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -864,144 +864,144 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 41 "49.bas" #line 1 "storestr2.asm" - + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication ; HL = address of string memory variable ; DE = address of 2n string. It just copies DE into (HL) ; freeing (HL) previously. - - - + + + __PISTORE_STR2: ; Indirect store temporary string at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR2: ld c, (hl) ; Dereferences HL inc hl ld h, (hl) ld l, c ; HL = *HL (real string variable address) - + __STORE_STR2: push hl ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = *HL (real string address) - + push de call __MEM_FREE pop de - + pop hl ld (hl), e inc hl ld (hl), d dec hl ; HL points to mem address variable. This might be useful in the future. - + ret - + #line 42 "49.bas" #line 1 "strslice.asm" - + ; String slicing library ; HL = Str pointer ; DE = String start ; BC = String character end ; A register => 0 => the HL pointer wont' be freed from the HEAP ; e.g. a$(5 TO 10) => HL = a$; DE = 5; BC = 10 - - ; This implements a$(X to Y) being X and Y first and + + ; This implements a$(X to Y) being X and Y first and ; last characters respectively. If X > Y, NULL is returned - + ; Otherwise returns a pointer to a$ FROM X to Y (starting from 0) ; if Y > len(a$), then a$ will be padded with spaces (reallocating - ; it in dynamic memory if needed). Returns pointer (HL) to resulting + ; it in dynamic memory if needed). Returns pointer (HL) to resulting ; string. NULL (0) if no memory for padding. ; - + #line 1 "strlen.asm" - + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL - + __STRLEN: ; Direct FASTCALL entry ld a, h or l ret z - + ld a, (hl) inc hl ld h, (hl) ; LEN(str) in HL ld l, a ret - - + + #line 18 "strslice.asm" - - - + + + __STRSLICE: ; Callee entry pop hl ; Return ADDRESS pop bc ; Last char pos pop de ; 1st char pos ex (sp), hl ; CALLEE. -> String start - + __STRSLICE_FAST: ; __FASTCALL__ Entry PROC - + LOCAL __CONT LOCAL __EMPTY LOCAL __FREE_ON_EXIT - + push hl ; Stores original HL pointer to be recovered on exit ex af, af' ; Saves A register for later - + push hl call __STRLEN - inc bc ; Last character position + 1 (string starts from 0) + inc bc ; Last character position + 1 (string starts from 0) or a sbc hl, bc ; Compares length with last char position jr nc, __CONT ; If Carry => We must copy to end of string @@ -1009,19 +1009,19 @@ __STRSLICE_FAST: ; __FASTCALL__ Entry ld b, h ld c, l ; Copy to the end of str ccf ; Clears Carry flag for next subtraction - + __CONT: - ld h, b + ld h, b ld l, c ; HL = Last char position to copy (1 for char 0, 2 for char 1, etc) sbc hl, de ; HL = LEN(a$) - DE => Number of chars to copy jr z, __EMPTY ; 0 Chars to copy => Return HL = 0 (NULL STR) jr c, __EMPTY ; If Carry => Nothing to return (NULL STR) - + ld b, h ld c, l ; BC = Number of chars to copy inc bc inc bc ; +2 bytes for string length number - + push bc push de call __MEM_ALLOC @@ -1030,15 +1030,15 @@ __CONT: ld a, h or l jr z, __EMPTY ; Return if NULL (no memory) - + dec bc dec bc ; Number of chars to copy (Len of slice) - + ld (hl), c inc hl ld (hl), b inc hl ; Stores new string length - + ex (sp), hl ; Pointer to A$ now in HL; Pointer to new string chars in Stack inc hl inc hl ; Skip string length @@ -1051,26 +1051,26 @@ __CONT: dec de ; Points to String LEN start ex de, hl ; Returns it in HL jr __FREE_ON_EXIT - + __EMPTY: ; Return NULL (empty) string pop hl ld hl, 0 ; Return NULL - - + + __FREE_ON_EXIT: ex af, af' ; Recover original A register ex (sp), hl ; Original HL pointer - + or a call nz, __MEM_FREE - + pop hl ; Recover result - ret - - ENDP - + ret + + ENDP + #line 43 "49.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/52.asm b/tests/functional/52.asm index 4f8c12f2d..9539c624d 100644 --- a/tests/functional/52.asm +++ b/tests/functional/52.asm @@ -32,7 +32,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFW 0001h diff --git a/tests/functional/54.asm b/tests/functional/54.asm index baab9c327..f783997d2 100644 --- a/tests/functional/54.asm +++ b/tests/functional/54.asm @@ -28,7 +28,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 04h diff --git a/tests/functional/55.asm b/tests/functional/55.asm index 88ed39ac0..189e202bb 100644 --- a/tests/functional/55.asm +++ b/tests/functional/55.asm @@ -37,10 +37,10 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "array.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ------------------------------------------------------------------- ; Simple array Index routine @@ -48,28 +48,28 @@ __CALL_BACK__: ; HL = Start of array memory (First two bytes contains N-1 dimensions) ; Dimension values on the stack, (top of the stack, highest dimension) ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> - + ; For any array of N dimension A(aN-1, ..., a1, a0) ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] ; What I will do here is to calculate the following sequence: ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... - - + + #line 1 "mul16.asm" - + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned - + PROC - + LOCAL __MUL16LOOP LOCAL __MUL16NOADD - + ex de, hl pop hl ; Return address ex (sp), hl ; CALLEE caller convention - + ;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand ;; ld c, h ;; ld a, l ; C,A => 1st Operand @@ -87,44 +87,44 @@ __MUL16: ; Mutiplies HL with the last value stored into de stack ;;__MUL16NOADD: ;; sla e ;; rl d - ;; + ;; ;; djnz __MUL16LOOP - + __MUL16_FAST: ld b, 16 ld a, d ld c, e ex de, hl ld hl, 0 - + __MUL16LOOP: add hl, hl ; hl << 1 sla c rla ; a,c << 1 jp nc, __MUL16NOADD add hl, de - + __MUL16NOADD: djnz __MUL16LOOP - + ret ; Result in hl (16 lower bits) - + ENDP - + #line 20 "array.asm" - + #line 24 "/src/zxb/trunk/library-asm/array.asm" - + __ARRAY: PROC - + LOCAL LOOP LOCAL ARRAY_END LOCAL RET_ADDRESS ; Stores return address - + ex (sp), hl ; Return address in HL, array address in the stack ld (RET_ADDRESS + 1), hl ; Stores it for later - + exx pop hl ; Will use H'L' as the pointer ld c, (hl) ; Loads Number of dimensions from (hl) @@ -132,23 +132,23 @@ __ARRAY: ld b, (hl) inc hl ; Ready exx - + ld hl, 0 ; BC = Offset "accumulator" - + #line 48 "/src/zxb/trunk/library-asm/array.asm" - + LOOP: pop bc ; Get next index (Ai) from the stack - + #line 60 "/src/zxb/trunk/library-asm/array.asm" - + add hl, bc ; Adds current index - + exx ; Checks if B'C' = 0 ld a, b ; Which means we must exit (last element is not multiplied by anything) or c jr z, ARRAY_END ; if B'Ci == 0 we are done - + ld e, (hl) ; Loads next dimension into D'E' inc hl ld d, (hl) @@ -157,13 +157,13 @@ LOOP: dec bc ; Decrements loop counter exx pop de ; DE = Max bound Number (i-th dimension) - + #line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL #line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP - + ARRAY_END: ld e, (hl) inc hl @@ -171,75 +171,75 @@ ARRAY_END: push hl push de exx - + #line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP - + ex de, hl ld hl, 0 pop bc ld b, c -ARRAY_SIZE_LOOP: +ARRAY_SIZE_LOOP: add hl, de djnz ARRAY_SIZE_LOOP - + ;; Even faster ;pop bc - + ;ld d, h ;ld e, l - + ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;dec c ;jp z, __ARRAY_FIN - + ;add hl, de - ;__ARRAY_FIN: + ;__ARRAY_FIN: #line 131 "/src/zxb/trunk/library-asm/array.asm" - + pop de add hl, de ; Adds element start - + RET_ADDRESS: ld de, 0 push de ret ; HL = (Start of Elements + Offset) - + ;; Performs a faster multiply for little 16bit numbs LOCAL __FNMUL, __FNMUL2 - + __FNMUL: xor a or d jp nz, __MUL16_FAST - + or e ex de, hl ret z - + cp 33 jp nc, __MUL16_FAST - + ld b, l ld l, h ; HL = 0 - + __FNMUL2: add hl, de djnz __FNMUL2 ret - + ENDP - + #line 28 "55.bas" - + ZXBASIC_USER_DATA: _a: DEFB 04h diff --git a/tests/functional/60.asm b/tests/functional/60.asm index 64e9e081e..c8e6cfc0d 100644 --- a/tests/functional/60.asm +++ b/tests/functional/60.asm @@ -36,7 +36,7 @@ _test__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/61.asm b/tests/functional/61.asm index 64e9e081e..c8e6cfc0d 100644 --- a/tests/functional/61.asm +++ b/tests/functional/61.asm @@ -36,7 +36,7 @@ _test__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/63.asm b/tests/functional/63.asm index ef497b655..cadc64b15 100644 --- a/tests/functional/63.asm +++ b/tests/functional/63.asm @@ -45,7 +45,7 @@ _test__leave: ex (sp), hl exx ret - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/64.asm b/tests/functional/64.asm index f21a32992..a82d1447e 100644 --- a/tests/functional/64.asm +++ b/tests/functional/64.asm @@ -31,7 +31,7 @@ __CALL_BACK__: _test: _test__leave: ret - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/65.asm b/tests/functional/65.asm index e11890586..4367aac7a 100644 --- a/tests/functional/65.asm +++ b/tests/functional/65.asm @@ -35,7 +35,7 @@ _test: ld (ix+5), a _test__leave: ret - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/66.asm b/tests/functional/66.asm index d0ff0fbeb..e2952139f 100644 --- a/tests/functional/66.asm +++ b/tests/functional/66.asm @@ -41,7 +41,7 @@ _test: ld (ix+5), a _test__leave: ret - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/70.asm b/tests/functional/70.asm index 7c8685224..c85ea7731 100644 --- a/tests/functional/70.asm +++ b/tests/functional/70.asm @@ -45,40 +45,40 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "cos.asm" - + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -94,78 +94,78 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 2 "cos.asm" - + COS: ; Computes COS using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 20h ; COS defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 36 "70.bas" #line 1 "exp.asm" - - - + + + EXP: ; Computes e^n using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 26h ; E^n defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 37 "70.bas" #line 1 "ftou32reg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "ftou32reg.asm" - + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) PROC - + LOCAL __IS_FLOAT - + or a - jr nz, __IS_FLOAT + jr nz, __IS_FLOAT ; Here if it is a ZX ROM Integer - + ld h, c ld l, d ld a, e ; Takes sign: FF = -, 0 = + @@ -173,107 +173,107 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS inc a jp z, __NEG32 ; Negates if negative ret - + __IS_FLOAT: ; Jumps here if it is a true floating point number - ld h, e + ld h, e push hl ; Stores it for later (Contains Sign in H) - + push de push bc - + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + ;ld a, c ; Get exponent sub 128 ; Exponent -= 128 jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 - + __FTOU32REG_LOOP: exx ; Shift C'B' E'D' << 1, output bit stays in Carry sla d rl e rl b rl c - + exx ; Shift DEHL << 1, inserting the carry on the right rl l rl h rl e rl d - + djnz __FTOU32REG_LOOP - + __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative jp m, __NEG32 ; Negates DEHL - + ret - + ENDP - - + + __FTOU8: ; Converts float in C ED LH to Unsigned byte in A call __FTOU32REG ld a, l ret - + #line 38 "70.bas" #line 1 "logn.asm" - - - + + + LN: ; Computes Ln(x) using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 20h ; 25h defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 39 "70.bas" #line 1 "sin.asm" - - - + + + SIN: ; Computes SIN using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 1Fh defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 40 "70.bas" #line 1 "sqrt.asm" - - - + + + SQRT: ; Computes SQRT(x) using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 28h ; SQRT defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 41 "70.bas" #line 1 "storef.asm" - + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -281,7 +281,7 @@ __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory pop hl ; HL <- IX add hl, de ; HL <- IX + HL pop de - + __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register ex af, af' ld a, (hl) @@ -289,7 +289,7 @@ __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address ld h, (hl) ld l, a ; HL = (HL) ex af, af' - + __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), a inc hl @@ -301,25 +301,25 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL inc hl ld (hl), b ret - + #line 42 "70.bas" #line 1 "tan.asm" - - - + + + TAN: ; Computes TAN using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 21h ; TAN defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 43 "70.bas" #line 1 "u32tofreg.asm" - - + + __I8TOFREG: ld l, a rlca @@ -327,35 +327,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -363,20 +363,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -384,32 +384,32 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 44 "70.bas" - + ZXBASIC_USER_DATA: _b: DEFB 00 diff --git a/tests/functional/abs.asm b/tests/functional/abs.asm index 0c5ff046c..3e6dd8206 100644 --- a/tests/functional/abs.asm +++ b/tests/functional/abs.asm @@ -30,7 +30,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/abs32.asm b/tests/functional/abs32.asm index c1fe68864..6c24a568a 100644 --- a/tests/functional/abs32.asm +++ b/tests/functional/abs32.asm @@ -32,46 +32,46 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "abs32.asm" - - ; 16 bit signed integer abs value + + ; 16 bit signed integer abs value ; HL = value - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 5 "abs32.asm" - + #line 23 "abs32.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00 diff --git a/tests/functional/add16.asm b/tests/functional/add16.asm index 7bc4dc8f7..954ec5f46 100644 --- a/tests/functional/add16.asm +++ b/tests/functional/add16.asm @@ -40,7 +40,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/add16a.asm b/tests/functional/add16a.asm index 142e7ce04..5505dc78b 100644 --- a/tests/functional/add16a.asm +++ b/tests/functional/add16a.asm @@ -33,7 +33,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/add16b.asm b/tests/functional/add16b.asm index 39973cc7f..8906a1745 100644 --- a/tests/functional/add16b.asm +++ b/tests/functional/add16b.asm @@ -40,7 +40,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/add32.asm b/tests/functional/add32.asm index 14d54fa81..eaac19a0b 100644 --- a/tests/functional/add32.asm +++ b/tests/functional/add32.asm @@ -64,7 +64,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00 diff --git a/tests/functional/add32a.asm b/tests/functional/add32a.asm index d53c03a7a..a49e545e3 100644 --- a/tests/functional/add32a.asm +++ b/tests/functional/add32a.asm @@ -42,7 +42,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00 diff --git a/tests/functional/add32b.asm b/tests/functional/add32b.asm index 95aee6ad6..bb8dc132d 100644 --- a/tests/functional/add32b.asm +++ b/tests/functional/add32b.asm @@ -57,7 +57,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00 diff --git a/tests/functional/add8.asm b/tests/functional/add8.asm index fdd2740e7..1aeebd29c 100644 --- a/tests/functional/add8.asm +++ b/tests/functional/add8.asm @@ -40,7 +40,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/add8a.asm b/tests/functional/add8a.asm index f27e18fbb..cc37bd76d 100644 --- a/tests/functional/add8a.asm +++ b/tests/functional/add8a.asm @@ -33,7 +33,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/add8b.asm b/tests/functional/add8b.asm index 93fedfb20..a60eb80d4 100644 --- a/tests/functional/add8b.asm +++ b/tests/functional/add8b.asm @@ -39,7 +39,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/addf16.asm b/tests/functional/addf16.asm index 08a654b88..0514142e9 100644 --- a/tests/functional/addf16.asm +++ b/tests/functional/addf16.asm @@ -64,7 +64,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00 diff --git a/tests/functional/addf16a.asm b/tests/functional/addf16a.asm index d53c03a7a..a49e545e3 100644 --- a/tests/functional/addf16a.asm +++ b/tests/functional/addf16a.asm @@ -42,7 +42,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00 diff --git a/tests/functional/addf16b.asm b/tests/functional/addf16b.asm index 8d2c5a4db..4fbf5b50f 100644 --- a/tests/functional/addf16b.asm +++ b/tests/functional/addf16b.asm @@ -57,7 +57,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00 diff --git a/tests/functional/addstr.asm b/tests/functional/addstr.asm index 9b4521f23..a12c7827e 100644 --- a/tests/functional/addstr.asm +++ b/tests/functional/addstr.asm @@ -65,19 +65,19 @@ __LABEL1: DEFW 0001h DEFB 31h #line 1 "storestr2.asm" - + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication ; HL = address of string memory variable ; DE = address of 2n string. It just copies DE into (HL) ; freeing (HL) previously. - + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -85,25 +85,25 @@ __LABEL1: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -112,41 +112,41 @@ __LABEL1: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -154,25 +154,25 @@ __LABEL1: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -181,39 +181,39 @@ __LABEL1: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -221,56 +221,56 @@ __LABEL1: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -279,57 +279,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -338,47 +338,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -388,49 +388,49 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 9 "storestr2.asm" - + __PISTORE_STR2: ; Indirect store temporary string at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR2: ld c, (hl) ; Dereferences HL inc hl ld h, (hl) ld l, c ; HL = *HL (real string variable address) - + __STORE_STR2: push hl ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = *HL (real string address) - + push de call __MEM_FREE pop de - + pop hl ld (hl), e inc hl ld (hl), d dec hl ; HL points to mem address variable. This might be useful in the future. - + ret - + #line 53 "addstr.bas" #line 1 "strcat.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -438,25 +438,25 @@ __STORE_STR2: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -465,51 +465,51 @@ __STORE_STR2: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -517,12 +517,12 @@ __STORE_STR2: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -530,16 +530,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -551,27 +551,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -583,7 +583,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -591,15 +591,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -624,14 +624,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -639,114 +639,114 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "strcat.asm" #line 1 "strlen.asm" - + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL - + __STRLEN: ; Direct FASTCALL entry ld a, h or l ret z - + ld a, (hl) inc hl ld h, (hl) ; LEN(str) in HL ld l, a ret - - + + #line 3 "strcat.asm" - + __ADDSTR: ; Implements c$ = a$ + b$ ; hl = &a$, de = &b$ (pointers) - - + + __STRCAT2: ; This routine creates a new string in dynamic space ; making room for it. Then copies a$ + b$ into it. ; HL = a$, DE = b$ - + PROC - + LOCAL __STR_CONT LOCAL __STRCATEND - + push hl call __STRLEN ld c, l ld b, h ; BC = LEN(a$) ex (sp), hl ; (SP) = LEN (a$), HL = a$ push hl ; Saves pointer to a$ - + inc bc inc bc ; +2 bytes to store length - + ex de, hl push hl call __STRLEN ; HL = len(b$) - + add hl, bc ; Total str length => 2 + len(a$) + len(b$) - + ld c, l ld b, h ; BC = Total str length + 2 - call __MEM_ALLOC - pop de ; HL = c$, DE = b$ - + call __MEM_ALLOC + pop de ; HL = c$, DE = b$ + ex de, hl ; HL = b$, DE = c$ - ex (sp), hl ; HL = a$, (SP) = b$ - + ex (sp), hl ; HL = a$, (SP) = b$ + exx - pop de ; D'E' = b$ + pop de ; D'E' = b$ exx - + pop bc ; LEN(a$) - + ld a, d or e ret z ; If no memory: RETURN - + __STR_CONT: push de ; Address of c$ - + ld a, h or l jr nz, __STR_CONT1 ; If len(a$) != 0 do copy - + ; a$ is NULL => uses HL = DE for transfer ld h, d ld l, e ld (hl), a ; This will copy 00 00 at (DE) location - inc de ; + inc de ; dec bc ; Ensure BC will be set to 1 in the next step - + __STR_CONT1: ; Copies a$ (HL) into c$ (DE) - inc bc + inc bc inc bc ; BC = BC + 2 ldir ; MEMCOPY: c$ = a$ pop hl ; HL = c$ - + exx push de ; Recovers b$; A ex hl,hl' would be very handy exx - - pop de ; DE = b$ - + + pop de ; DE = b$ + __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ; NOTE: Both DE, BC and AF are modified and lost ; Returns HL (pointer to a$) @@ -754,50 +754,50 @@ __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ld a, d or e ret z ; Returns if de is NULL (nothing to copy) - + push hl ; Saves HL to return it later - + ld c, (hl) inc hl ld b, (hl) inc hl add hl, bc ; HL = end of (a$) string ; bc = len(a$) push bc ; Saves LEN(a$) for later - + ex de, hl ; DE = end of string (Begin of copy addr) ld c, (hl) inc hl ld b, (hl) ; BC = len(b$) - + ld a, b or c jr z, __STRCATEND; Return if len(b$) == 0 - + push bc ; Save LEN(b$) inc hl ; Skip 2nd byte of len(b$) ldir ; Concatenate b$ - + pop bc ; Recovers length (b$) pop hl ; Recovers length (a$) add hl, bc ; HL = LEN(a$) + LEN(b$) = LEN(a$+b$) ex de, hl ; DE = LEN(a$+b$) pop hl - + ld (hl), e ; Updates new LEN and return inc hl ld (hl), d dec hl ret - + __STRCATEND: pop hl ; Removes Len(a$) pop hl ; Restores original HL, so HL = a$ ret - + ENDP - + #line 54 "addstr.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/aloadstr0.asm b/tests/functional/aloadstr0.asm index 1bfc2a8fb..f0804dcb7 100644 --- a/tests/functional/aloadstr0.asm +++ b/tests/functional/aloadstr0.asm @@ -35,12 +35,12 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -48,25 +48,25 @@ __CALL_BACK__: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -75,51 +75,51 @@ __CALL_BACK__: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -127,12 +127,12 @@ __CALL_BACK__: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -140,7 +140,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -148,10 +148,10 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -159,25 +159,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -186,39 +186,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -226,57 +226,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -288,27 +288,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -320,7 +320,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -328,15 +328,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -361,14 +361,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -376,25 +376,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -403,30 +403,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -434,19 +434,19 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 23 "aloadstr0.bas" #line 1 "storestr2.asm" - + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication ; HL = address of string memory variable ; DE = address of 2n string. It just copies DE into (HL) ; freeing (HL) previously. - + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -454,25 +454,25 @@ __LOADSTR: ; __FASTCALL__ entry ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -481,38 +481,38 @@ __LOADSTR: ; __FASTCALL__ entry ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -521,57 +521,57 @@ __LOADSTR: ; __FASTCALL__ entry ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -580,47 +580,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -630,43 +630,43 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 9 "storestr2.asm" - + __PISTORE_STR2: ; Indirect store temporary string at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR2: ld c, (hl) ; Dereferences HL inc hl ld h, (hl) ld l, c ; HL = *HL (real string variable address) - + __STORE_STR2: push hl ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = *HL (real string address) - + push de call __MEM_FREE pop de - + pop hl ld (hl), e inc hl ld (hl), d dec hl ; HL points to mem address variable. This might be useful in the future. - + ret - + #line 24 "aloadstr0.bas" - + ZXBASIC_USER_DATA: _b: DEFB 00, 00 diff --git a/tests/functional/aloadstr1.asm b/tests/functional/aloadstr1.asm index b28d01b0b..6cf9729cc 100644 --- a/tests/functional/aloadstr1.asm +++ b/tests/functional/aloadstr1.asm @@ -40,10 +40,10 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "array.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ------------------------------------------------------------------- ; Simple array Index routine @@ -51,28 +51,28 @@ __CALL_BACK__: ; HL = Start of array memory (First two bytes contains N-1 dimensions) ; Dimension values on the stack, (top of the stack, highest dimension) ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> - + ; For any array of N dimension A(aN-1, ..., a1, a0) ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] ; What I will do here is to calculate the following sequence: ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... - - + + #line 1 "mul16.asm" - + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned - + PROC - + LOCAL __MUL16LOOP LOCAL __MUL16NOADD - + ex de, hl pop hl ; Return address ex (sp), hl ; CALLEE caller convention - + ;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand ;; ld c, h ;; ld a, l ; C,A => 1st Operand @@ -90,44 +90,44 @@ __MUL16: ; Mutiplies HL with the last value stored into de stack ;;__MUL16NOADD: ;; sla e ;; rl d - ;; + ;; ;; djnz __MUL16LOOP - + __MUL16_FAST: ld b, 16 ld a, d ld c, e ex de, hl ld hl, 0 - + __MUL16LOOP: add hl, hl ; hl << 1 sla c rla ; a,c << 1 jp nc, __MUL16NOADD add hl, de - + __MUL16NOADD: djnz __MUL16LOOP - + ret ; Result in hl (16 lower bits) - + ENDP - + #line 20 "array.asm" - + #line 24 "/src/zxb/trunk/library-asm/array.asm" - + __ARRAY: PROC - + LOCAL LOOP LOCAL ARRAY_END LOCAL RET_ADDRESS ; Stores return address - + ex (sp), hl ; Return address in HL, array address in the stack ld (RET_ADDRESS + 1), hl ; Stores it for later - + exx pop hl ; Will use H'L' as the pointer ld c, (hl) ; Loads Number of dimensions from (hl) @@ -135,23 +135,23 @@ __ARRAY: ld b, (hl) inc hl ; Ready exx - + ld hl, 0 ; BC = Offset "accumulator" - + #line 48 "/src/zxb/trunk/library-asm/array.asm" - + LOOP: pop bc ; Get next index (Ai) from the stack - + #line 60 "/src/zxb/trunk/library-asm/array.asm" - + add hl, bc ; Adds current index - + exx ; Checks if B'C' = 0 ld a, b ; Which means we must exit (last element is not multiplied by anything) or c jr z, ARRAY_END ; if B'Ci == 0 we are done - + ld e, (hl) ; Loads next dimension into D'E' inc hl ld d, (hl) @@ -160,13 +160,13 @@ LOOP: dec bc ; Decrements loop counter exx pop de ; DE = Max bound Number (i-th dimension) - + #line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL #line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP - + ARRAY_END: ld e, (hl) inc hl @@ -174,81 +174,81 @@ ARRAY_END: push hl push de exx - + #line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP - + ex de, hl ld hl, 0 pop bc ld b, c -ARRAY_SIZE_LOOP: +ARRAY_SIZE_LOOP: add hl, de djnz ARRAY_SIZE_LOOP - + ;; Even faster ;pop bc - + ;ld d, h ;ld e, l - + ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;dec c ;jp z, __ARRAY_FIN - + ;add hl, de - ;__ARRAY_FIN: + ;__ARRAY_FIN: #line 131 "/src/zxb/trunk/library-asm/array.asm" - + pop de add hl, de ; Adds element start - + RET_ADDRESS: ld de, 0 push de ret ; HL = (Start of Elements + Offset) - + ;; Performs a faster multiply for little 16bit numbs LOCAL __FNMUL, __FNMUL2 - + __FNMUL: xor a or d jp nz, __MUL16_FAST - + or e ex de, hl ret z - + cp 33 jp nc, __MUL16_FAST - + ld b, l ld l, h ; HL = 0 - + __FNMUL2: add hl, de djnz __FNMUL2 ret - + ENDP - + #line 28 "aloadstr1.bas" #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -256,25 +256,25 @@ __FNMUL2: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -283,51 +283,51 @@ __FNMUL2: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -335,12 +335,12 @@ __FNMUL2: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -348,7 +348,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -356,10 +356,10 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -367,25 +367,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -394,39 +394,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -434,57 +434,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -496,27 +496,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -528,7 +528,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -536,15 +536,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -569,14 +569,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -584,25 +584,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -611,30 +611,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -642,19 +642,19 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 29 "aloadstr1.bas" #line 1 "storestr2.asm" - + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication ; HL = address of string memory variable ; DE = address of 2n string. It just copies DE into (HL) ; freeing (HL) previously. - + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -662,25 +662,25 @@ __LOADSTR: ; __FASTCALL__ entry ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -689,38 +689,38 @@ __LOADSTR: ; __FASTCALL__ entry ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -729,57 +729,57 @@ __LOADSTR: ; __FASTCALL__ entry ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -788,47 +788,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -838,43 +838,43 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 9 "storestr2.asm" - + __PISTORE_STR2: ; Indirect store temporary string at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR2: ld c, (hl) ; Dereferences HL inc hl ld h, (hl) ld l, c ; HL = *HL (real string variable address) - + __STORE_STR2: push hl ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = *HL (real string address) - + push de call __MEM_FREE pop de - + pop hl ld (hl), e inc hl ld (hl), d dec hl ; HL points to mem address variable. This might be useful in the future. - + ret - + #line 30 "aloadstr1.bas" - + ZXBASIC_USER_DATA: _c: DEFB 00 diff --git a/tests/functional/and16.asm b/tests/functional/and16.asm index be06d866a..3b7d3e507 100644 --- a/tests/functional/and16.asm +++ b/tests/functional/and16.asm @@ -45,23 +45,23 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "and16.asm" - + ; FASTCALL boolean and 16 version. ; result in Accumulator (0 False, not 0 True) ; __FASTCALL__ version (operands: DE, HL) ; Performs 16bit and 16bit and returns the boolean - + __AND16: ld a, h or l ret z - + ld a, d or e - ret - + ret + #line 36 "and16.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/and32.asm b/tests/functional/and32.asm index 4b49a32f1..b93fc8569 100644 --- a/tests/functional/and32.asm +++ b/tests/functional/and32.asm @@ -55,24 +55,24 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "and32.asm" - + ; FASTCALL boolean and 32 version. ; Performs 32bit and 32bit and returns the boolean ; result in Accumulator (0 False, not 0 True) ; First operand in DE,HL 2nd operand into the stack - + __AND32: ld a, l or h or e or d - sub 1 + sub 1 sbc a - + ld c, a - + pop hl - + pop de ld a, d or e @@ -81,14 +81,14 @@ __AND32: or e sub 1 sbc a - + or c cpl jp (hl) - - + + #line 46 "and32.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00 diff --git a/tests/functional/and8.asm b/tests/functional/and8.asm index edc664afd..134680a99 100644 --- a/tests/functional/and8.asm +++ b/tests/functional/and8.asm @@ -41,20 +41,20 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "and8.asm" - + ; FASTCALL boolean and 8 version. ; result in Accumulator (0 False, not 0 True) ; __FASTCALL__ version (operands: A, H) ; Performs 8bit and 8bit and returns the boolean - + __AND8: or a ret z ld a, h - ret - + ret + #line 32 "and8.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/arden2.asm b/tests/functional/arden2.asm index 607d1b825..d64ad7bb3 100644 --- a/tests/functional/arden2.asm +++ b/tests/functional/arden2.asm @@ -45,10 +45,10 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -56,25 +56,25 @@ __CALL_BACK__: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -83,51 +83,51 @@ __CALL_BACK__: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -135,12 +135,12 @@ __CALL_BACK__: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -148,7 +148,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -156,10 +156,10 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -167,25 +167,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -194,39 +194,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -234,57 +234,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -296,27 +296,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -328,7 +328,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -336,15 +336,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -369,14 +369,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -384,112 +384,112 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 33 "arden2.bas" #line 1 "chr.asm" - + ; CHR$(x, y, x) returns the string CHR$(x) + CHR$(y) + CHR$(z) ; - - - + + + CHR: ; Returns HL = Pointer to STRING (NULL if no memory) ; Requires alloc.asm for dynamic memory heap. ; Parameters: HL = Number of bytes to insert (already push onto the stack) ; STACK => parameters (16 bit, only the High byte is considered) ; Used registers A, A', BC, DE, HL, H'L' - + PROC - + LOCAL __POPOUT LOCAL TMP - + TMP EQU 23629 ; (DEST System variable) - + ld a, h or l ret z ; If Number of parameters is ZERO, return NULL STRING - + ld b, h ld c, l - + pop hl ; Return address ld (TMP), hl - + push bc inc bc inc bc ; BC = BC + 2 => (2 bytes for the length number) call __MEM_ALLOC pop bc - + ld d, h ld e, l ; Saves HL in DE - + ld a, h or l jr z, __POPOUT ; No Memory, return - + ld (hl), c inc hl ld (hl), b inc hl - + __POPOUT: ; Removes out of the stack every byte and return ; If Zero Flag is set, don't store bytes in memory - ex af, af' ; Save Zero Flag - + ex af, af' ; Save Zero Flag + ld a, b or c jr z, __CHR_END - + dec bc pop af ; Next byte - + ex af, af' ; Recovers Zero flag jr z, __POPOUT - + ex af, af' ; Saves Zero flag ld (hl), a inc hl ex af, af' ; Recovers Zero Flag - + jp __POPOUT - + __CHR_END: ld hl, (TMP) push hl ; Restores return addr ex de, hl ; Recovers original HL ptr ret - + ENDP - + #line 34 "arden2.bas" #line 1 "storestr2.asm" - + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication ; HL = address of string memory variable ; DE = address of 2n string. It just copies DE into (HL) ; freeing (HL) previously. - + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -497,25 +497,25 @@ __CHR_END: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -524,38 +524,38 @@ __CHR_END: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -564,57 +564,57 @@ __CHR_END: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -623,47 +623,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -673,139 +673,139 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 9 "storestr2.asm" - + __PISTORE_STR2: ; Indirect store temporary string at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR2: ld c, (hl) ; Dereferences HL inc hl ld h, (hl) ld l, c ; HL = *HL (real string variable address) - + __STORE_STR2: push hl ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = *HL (real string address) - + push de call __MEM_FREE pop de - + pop hl ld (hl), e inc hl ld (hl), d dec hl ; HL points to mem address variable. This might be useful in the future. - + ret - + #line 35 "arden2.bas" #line 1 "strcat.asm" - - + + #line 1 "strlen.asm" - + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL - + __STRLEN: ; Direct FASTCALL entry ld a, h or l ret z - + ld a, (hl) inc hl ld h, (hl) ; LEN(str) in HL ld l, a ret - - + + #line 3 "strcat.asm" - + __ADDSTR: ; Implements c$ = a$ + b$ ; hl = &a$, de = &b$ (pointers) - - + + __STRCAT2: ; This routine creates a new string in dynamic space ; making room for it. Then copies a$ + b$ into it. ; HL = a$, DE = b$ - + PROC - + LOCAL __STR_CONT LOCAL __STRCATEND - + push hl call __STRLEN ld c, l ld b, h ; BC = LEN(a$) ex (sp), hl ; (SP) = LEN (a$), HL = a$ push hl ; Saves pointer to a$ - + inc bc inc bc ; +2 bytes to store length - + ex de, hl push hl call __STRLEN ; HL = len(b$) - + add hl, bc ; Total str length => 2 + len(a$) + len(b$) - + ld c, l ld b, h ; BC = Total str length + 2 - call __MEM_ALLOC - pop de ; HL = c$, DE = b$ - + call __MEM_ALLOC + pop de ; HL = c$, DE = b$ + ex de, hl ; HL = b$, DE = c$ - ex (sp), hl ; HL = a$, (SP) = b$ - + ex (sp), hl ; HL = a$, (SP) = b$ + exx - pop de ; D'E' = b$ + pop de ; D'E' = b$ exx - + pop bc ; LEN(a$) - + ld a, d or e ret z ; If no memory: RETURN - + __STR_CONT: push de ; Address of c$ - + ld a, h or l jr nz, __STR_CONT1 ; If len(a$) != 0 do copy - + ; a$ is NULL => uses HL = DE for transfer ld h, d ld l, e ld (hl), a ; This will copy 00 00 at (DE) location - inc de ; + inc de ; dec bc ; Ensure BC will be set to 1 in the next step - + __STR_CONT1: ; Copies a$ (HL) into c$ (DE) - inc bc + inc bc inc bc ; BC = BC + 2 ldir ; MEMCOPY: c$ = a$ pop hl ; HL = c$ - + exx push de ; Recovers b$; A ex hl,hl' would be very handy exx - - pop de ; DE = b$ - + + pop de ; DE = b$ + __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ; NOTE: Both DE, BC and AF are modified and lost ; Returns HL (pointer to a$) @@ -813,50 +813,50 @@ __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ld a, d or e ret z ; Returns if de is NULL (nothing to copy) - + push hl ; Saves HL to return it later - + ld c, (hl) inc hl ld b, (hl) inc hl add hl, bc ; HL = end of (a$) string ; bc = len(a$) push bc ; Saves LEN(a$) for later - + ex de, hl ; DE = end of string (Begin of copy addr) ld c, (hl) inc hl ld b, (hl) ; BC = len(b$) - + ld a, b or c jr z, __STRCATEND; Return if len(b$) == 0 - + push bc ; Save LEN(b$) inc hl ; Skip 2nd byte of len(b$) ldir ; Concatenate b$ - + pop bc ; Recovers length (b$) pop hl ; Recovers length (a$) add hl, bc ; HL = LEN(a$) + LEN(b$) = LEN(a$+b$) ex de, hl ; DE = LEN(a$+b$) pop hl - + ld (hl), e ; Updates new LEN and return inc hl ld (hl), d dec hl ret - + __STRCATEND: pop hl ; Removes Len(a$) pop hl ; Restores original HL, so HL = a$ ret - + ENDP - + #line 36 "arden2.bas" - + ZXBASIC_USER_DATA: _c: DEFB 00, 00 diff --git a/tests/functional/array00.asm b/tests/functional/array00.asm index 6d0db0f24..db537295a 100644 --- a/tests/functional/array00.asm +++ b/tests/functional/array00.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _bufferx: DEFW 0001h diff --git a/tests/functional/array01.asm b/tests/functional/array01.asm index 56f683953..67927b229 100644 --- a/tests/functional/array01.asm +++ b/tests/functional/array01.asm @@ -28,7 +28,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFW 0000h diff --git a/tests/functional/array02.asm b/tests/functional/array02.asm index 4073622e3..2540b9393 100644 --- a/tests/functional/array02.asm +++ b/tests/functional/array02.asm @@ -28,7 +28,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _b: DEFB 00 diff --git a/tests/functional/array03.asm b/tests/functional/array03.asm index 41211ce29..630631c9a 100644 --- a/tests/functional/array03.asm +++ b/tests/functional/array03.asm @@ -35,10 +35,10 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "array.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ------------------------------------------------------------------- ; Simple array Index routine @@ -46,28 +46,28 @@ __CALL_BACK__: ; HL = Start of array memory (First two bytes contains N-1 dimensions) ; Dimension values on the stack, (top of the stack, highest dimension) ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> - + ; For any array of N dimension A(aN-1, ..., a1, a0) ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] ; What I will do here is to calculate the following sequence: ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... - - + + #line 1 "mul16.asm" - + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned - + PROC - + LOCAL __MUL16LOOP LOCAL __MUL16NOADD - + ex de, hl pop hl ; Return address ex (sp), hl ; CALLEE caller convention - + ;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand ;; ld c, h ;; ld a, l ; C,A => 1st Operand @@ -85,44 +85,44 @@ __MUL16: ; Mutiplies HL with the last value stored into de stack ;;__MUL16NOADD: ;; sla e ;; rl d - ;; + ;; ;; djnz __MUL16LOOP - + __MUL16_FAST: ld b, 16 ld a, d ld c, e ex de, hl ld hl, 0 - + __MUL16LOOP: add hl, hl ; hl << 1 sla c rla ; a,c << 1 jp nc, __MUL16NOADD add hl, de - + __MUL16NOADD: djnz __MUL16LOOP - + ret ; Result in hl (16 lower bits) - + ENDP - + #line 20 "array.asm" - + #line 24 "/src/zxb/trunk/library-asm/array.asm" - + __ARRAY: PROC - + LOCAL LOOP LOCAL ARRAY_END LOCAL RET_ADDRESS ; Stores return address - + ex (sp), hl ; Return address in HL, array address in the stack ld (RET_ADDRESS + 1), hl ; Stores it for later - + exx pop hl ; Will use H'L' as the pointer ld c, (hl) ; Loads Number of dimensions from (hl) @@ -130,23 +130,23 @@ __ARRAY: ld b, (hl) inc hl ; Ready exx - + ld hl, 0 ; BC = Offset "accumulator" - + #line 48 "/src/zxb/trunk/library-asm/array.asm" - + LOOP: pop bc ; Get next index (Ai) from the stack - + #line 60 "/src/zxb/trunk/library-asm/array.asm" - + add hl, bc ; Adds current index - + exx ; Checks if B'C' = 0 ld a, b ; Which means we must exit (last element is not multiplied by anything) or c jr z, ARRAY_END ; if B'Ci == 0 we are done - + ld e, (hl) ; Loads next dimension into D'E' inc hl ld d, (hl) @@ -155,13 +155,13 @@ LOOP: dec bc ; Decrements loop counter exx pop de ; DE = Max bound Number (i-th dimension) - + #line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL #line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP - + ARRAY_END: ld e, (hl) inc hl @@ -169,75 +169,75 @@ ARRAY_END: push hl push de exx - + #line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP - + ex de, hl ld hl, 0 pop bc ld b, c -ARRAY_SIZE_LOOP: +ARRAY_SIZE_LOOP: add hl, de djnz ARRAY_SIZE_LOOP - + ;; Even faster ;pop bc - + ;ld d, h ;ld e, l - + ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;dec c ;jp z, __ARRAY_FIN - + ;add hl, de - ;__ARRAY_FIN: + ;__ARRAY_FIN: #line 131 "/src/zxb/trunk/library-asm/array.asm" - + pop de add hl, de ; Adds element start - + RET_ADDRESS: ld de, 0 push de ret ; HL = (Start of Elements + Offset) - + ;; Performs a faster multiply for little 16bit numbs LOCAL __FNMUL, __FNMUL2 - + __FNMUL: xor a or d jp nz, __MUL16_FAST - + or e ex de, hl ret z - + cp 33 jp nc, __MUL16_FAST - + ld b, l ld l, h ; HL = 0 - + __FNMUL2: add hl, de djnz __FNMUL2 ret - + ENDP - + #line 26 "array03.bas" - + ZXBASIC_USER_DATA: _b: DEFB 00 diff --git a/tests/functional/array04.asm b/tests/functional/array04.asm index 80e5cb258..e24942ab3 100644 --- a/tests/functional/array04.asm +++ b/tests/functional/array04.asm @@ -28,7 +28,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFW 0000h diff --git a/tests/functional/array05.asm b/tests/functional/array05.asm index 119d1bd37..68e6de0ab 100644 --- a/tests/functional/array05.asm +++ b/tests/functional/array05.asm @@ -28,7 +28,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _b: DEFB 00, 00 diff --git a/tests/functional/array06.asm b/tests/functional/array06.asm index 273e9ef70..d4ddedce3 100644 --- a/tests/functional/array06.asm +++ b/tests/functional/array06.asm @@ -35,10 +35,10 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "array.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ------------------------------------------------------------------- ; Simple array Index routine @@ -46,28 +46,28 @@ __CALL_BACK__: ; HL = Start of array memory (First two bytes contains N-1 dimensions) ; Dimension values on the stack, (top of the stack, highest dimension) ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> - + ; For any array of N dimension A(aN-1, ..., a1, a0) ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] ; What I will do here is to calculate the following sequence: ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... - - + + #line 1 "mul16.asm" - + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned - + PROC - + LOCAL __MUL16LOOP LOCAL __MUL16NOADD - + ex de, hl pop hl ; Return address ex (sp), hl ; CALLEE caller convention - + ;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand ;; ld c, h ;; ld a, l ; C,A => 1st Operand @@ -85,44 +85,44 @@ __MUL16: ; Mutiplies HL with the last value stored into de stack ;;__MUL16NOADD: ;; sla e ;; rl d - ;; + ;; ;; djnz __MUL16LOOP - + __MUL16_FAST: ld b, 16 ld a, d ld c, e ex de, hl ld hl, 0 - + __MUL16LOOP: add hl, hl ; hl << 1 sla c rla ; a,c << 1 jp nc, __MUL16NOADD add hl, de - + __MUL16NOADD: djnz __MUL16LOOP - + ret ; Result in hl (16 lower bits) - + ENDP - + #line 20 "array.asm" - + #line 24 "/src/zxb/trunk/library-asm/array.asm" - + __ARRAY: PROC - + LOCAL LOOP LOCAL ARRAY_END LOCAL RET_ADDRESS ; Stores return address - + ex (sp), hl ; Return address in HL, array address in the stack ld (RET_ADDRESS + 1), hl ; Stores it for later - + exx pop hl ; Will use H'L' as the pointer ld c, (hl) ; Loads Number of dimensions from (hl) @@ -130,23 +130,23 @@ __ARRAY: ld b, (hl) inc hl ; Ready exx - + ld hl, 0 ; BC = Offset "accumulator" - + #line 48 "/src/zxb/trunk/library-asm/array.asm" - + LOOP: pop bc ; Get next index (Ai) from the stack - + #line 60 "/src/zxb/trunk/library-asm/array.asm" - + add hl, bc ; Adds current index - + exx ; Checks if B'C' = 0 ld a, b ; Which means we must exit (last element is not multiplied by anything) or c jr z, ARRAY_END ; if B'Ci == 0 we are done - + ld e, (hl) ; Loads next dimension into D'E' inc hl ld d, (hl) @@ -155,13 +155,13 @@ LOOP: dec bc ; Decrements loop counter exx pop de ; DE = Max bound Number (i-th dimension) - + #line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL #line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP - + ARRAY_END: ld e, (hl) inc hl @@ -169,75 +169,75 @@ ARRAY_END: push hl push de exx - + #line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP - + ex de, hl ld hl, 0 pop bc ld b, c -ARRAY_SIZE_LOOP: +ARRAY_SIZE_LOOP: add hl, de djnz ARRAY_SIZE_LOOP - + ;; Even faster ;pop bc - + ;ld d, h ;ld e, l - + ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;dec c ;jp z, __ARRAY_FIN - + ;add hl, de - ;__ARRAY_FIN: + ;__ARRAY_FIN: #line 131 "/src/zxb/trunk/library-asm/array.asm" - + pop de add hl, de ; Adds element start - + RET_ADDRESS: ld de, 0 push de ret ; HL = (Start of Elements + Offset) - + ;; Performs a faster multiply for little 16bit numbs LOCAL __FNMUL, __FNMUL2 - + __FNMUL: xor a or d jp nz, __MUL16_FAST - + or e ex de, hl ret z - + cp 33 jp nc, __MUL16_FAST - + ld b, l ld l, h ; HL = 0 - + __FNMUL2: add hl, de djnz __FNMUL2 ret - + ENDP - + #line 26 "array06.bas" - + ZXBASIC_USER_DATA: _b: DEFB 00, 00 diff --git a/tests/functional/array07.asm b/tests/functional/array07.asm index b32426267..67710ccdb 100644 --- a/tests/functional/array07.asm +++ b/tests/functional/array07.asm @@ -58,10 +58,10 @@ _test__leave: exx ret #line 1 "array.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ------------------------------------------------------------------- ; Simple array Index routine @@ -69,28 +69,28 @@ _test__leave: ; HL = Start of array memory (First two bytes contains N-1 dimensions) ; Dimension values on the stack, (top of the stack, highest dimension) ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> - + ; For any array of N dimension A(aN-1, ..., a1, a0) ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] ; What I will do here is to calculate the following sequence: ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... - - + + #line 1 "mul16.asm" - + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned - + PROC - + LOCAL __MUL16LOOP LOCAL __MUL16NOADD - + ex de, hl pop hl ; Return address ex (sp), hl ; CALLEE caller convention - + ;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand ;; ld c, h ;; ld a, l ; C,A => 1st Operand @@ -108,44 +108,44 @@ __MUL16: ; Mutiplies HL with the last value stored into de stack ;;__MUL16NOADD: ;; sla e ;; rl d - ;; + ;; ;; djnz __MUL16LOOP - + __MUL16_FAST: ld b, 16 ld a, d ld c, e ex de, hl ld hl, 0 - + __MUL16LOOP: add hl, hl ; hl << 1 sla c rla ; a,c << 1 jp nc, __MUL16NOADD add hl, de - + __MUL16NOADD: djnz __MUL16LOOP - + ret ; Result in hl (16 lower bits) - + ENDP - + #line 20 "array.asm" - + #line 24 "/src/zxb/trunk/library-asm/array.asm" - + __ARRAY: PROC - + LOCAL LOOP LOCAL ARRAY_END LOCAL RET_ADDRESS ; Stores return address - + ex (sp), hl ; Return address in HL, array address in the stack ld (RET_ADDRESS + 1), hl ; Stores it for later - + exx pop hl ; Will use H'L' as the pointer ld c, (hl) ; Loads Number of dimensions from (hl) @@ -153,23 +153,23 @@ __ARRAY: ld b, (hl) inc hl ; Ready exx - + ld hl, 0 ; BC = Offset "accumulator" - + #line 48 "/src/zxb/trunk/library-asm/array.asm" - + LOOP: pop bc ; Get next index (Ai) from the stack - + #line 60 "/src/zxb/trunk/library-asm/array.asm" - + add hl, bc ; Adds current index - + exx ; Checks if B'C' = 0 ld a, b ; Which means we must exit (last element is not multiplied by anything) or c jr z, ARRAY_END ; if B'Ci == 0 we are done - + ld e, (hl) ; Loads next dimension into D'E' inc hl ld d, (hl) @@ -178,13 +178,13 @@ LOOP: dec bc ; Decrements loop counter exx pop de ; DE = Max bound Number (i-th dimension) - + #line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL #line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP - + ARRAY_END: ld e, (hl) inc hl @@ -192,79 +192,79 @@ ARRAY_END: push hl push de exx - + #line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP - + ex de, hl ld hl, 0 pop bc ld b, c -ARRAY_SIZE_LOOP: +ARRAY_SIZE_LOOP: add hl, de djnz ARRAY_SIZE_LOOP - + ;; Even faster ;pop bc - + ;ld d, h ;ld e, l - + ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;dec c ;jp z, __ARRAY_FIN - + ;add hl, de - ;__ARRAY_FIN: + ;__ARRAY_FIN: #line 131 "/src/zxb/trunk/library-asm/array.asm" - + pop de add hl, de ; Adds element start - + RET_ADDRESS: ld de, 0 push de ret ; HL = (Start of Elements + Offset) - + ;; Performs a faster multiply for little 16bit numbs LOCAL __FNMUL, __FNMUL2 - + __FNMUL: xor a or d jp nz, __MUL16_FAST - + or e ex de, hl ret z - + cp 33 jp nc, __MUL16_FAST - + ld b, l ld l, h ; HL = 0 - + __FNMUL2: add hl, de djnz __FNMUL2 ret - + ENDP - + #line 46 "array07.bas" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -272,25 +272,25 @@ __FNMUL2: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -299,41 +299,41 @@ __FNMUL2: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -341,25 +341,25 @@ __FNMUL2: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -368,39 +368,39 @@ __FNMUL2: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -408,56 +408,56 @@ __FNMUL2: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -466,57 +466,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -525,47 +525,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -575,12 +575,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 47 "array07.bas" #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -591,15 +591,15 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -607,25 +607,25 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -634,52 +634,52 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -687,12 +687,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -700,7 +700,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -708,10 +708,10 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -719,25 +719,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -746,40 +746,40 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - - + + + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -791,27 +791,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -823,7 +823,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -831,15 +831,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -864,14 +864,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -879,23 +879,23 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 71 "realloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -914,29 +914,29 @@ __MEM_SUBTRACT: ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -945,111 +945,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -1065,7 +1065,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -1073,44 +1073,44 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 48 "array07.bas" - + ZXBASIC_USER_DATA: _b: DEFB 00, 00 diff --git a/tests/functional/array08.asm b/tests/functional/array08.asm index 1de8e36eb..264cc06f7 100644 --- a/tests/functional/array08.asm +++ b/tests/functional/array08.asm @@ -36,10 +36,10 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "array.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ------------------------------------------------------------------- ; Simple array Index routine @@ -47,28 +47,28 @@ __CALL_BACK__: ; HL = Start of array memory (First two bytes contains N-1 dimensions) ; Dimension values on the stack, (top of the stack, highest dimension) ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> - + ; For any array of N dimension A(aN-1, ..., a1, a0) ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] ; What I will do here is to calculate the following sequence: ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... - - + + #line 1 "mul16.asm" - + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned - + PROC - + LOCAL __MUL16LOOP LOCAL __MUL16NOADD - + ex de, hl pop hl ; Return address ex (sp), hl ; CALLEE caller convention - + ;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand ;; ld c, h ;; ld a, l ; C,A => 1st Operand @@ -86,44 +86,44 @@ __MUL16: ; Mutiplies HL with the last value stored into de stack ;;__MUL16NOADD: ;; sla e ;; rl d - ;; + ;; ;; djnz __MUL16LOOP - + __MUL16_FAST: ld b, 16 ld a, d ld c, e ex de, hl ld hl, 0 - + __MUL16LOOP: add hl, hl ; hl << 1 sla c rla ; a,c << 1 jp nc, __MUL16NOADD add hl, de - + __MUL16NOADD: djnz __MUL16LOOP - + ret ; Result in hl (16 lower bits) - + ENDP - + #line 20 "array.asm" - -#line 24 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" - + +#line 24 "/src/zxb/trunk/library-asm/array.asm" + __ARRAY: PROC - + LOCAL LOOP LOCAL ARRAY_END LOCAL RET_ADDRESS ; Stores return address - + ex (sp), hl ; Return address in HL, array address in the stack ld (RET_ADDRESS + 1), hl ; Stores it for later - + exx pop hl ; Will use H'L' as the pointer ld c, (hl) ; Loads Number of dimensions from (hl) @@ -131,23 +131,23 @@ __ARRAY: ld b, (hl) inc hl ; Ready exx - + ld hl, 0 ; BC = Offset "accumulator" - -#line 48 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" - + +#line 48 "/src/zxb/trunk/library-asm/array.asm" + LOOP: pop bc ; Get next index (Ai) from the stack - -#line 60 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" - + +#line 60 "/src/zxb/trunk/library-asm/array.asm" + add hl, bc ; Adds current index - + exx ; Checks if B'C' = 0 ld a, b ; Which means we must exit (last element is not multiplied by anything) or c jr z, ARRAY_END ; if B'Ci == 0 we are done - + ld e, (hl) ; Loads next dimension into D'E' inc hl ld d, (hl) @@ -156,13 +156,13 @@ LOOP: dec bc ; Decrements loop counter exx pop de ; DE = Max bound Number (i-th dimension) - -#line 80 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" + +#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" +#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP - + ARRAY_END: ld e, (hl) inc hl @@ -170,76 +170,76 @@ ARRAY_END: push hl push de exx - -#line 100 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" + +#line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP - + ex de, hl ld hl, 0 pop bc ld b, c -ARRAY_SIZE_LOOP: +ARRAY_SIZE_LOOP: add hl, de djnz ARRAY_SIZE_LOOP - + ;; Even faster ;pop bc - + ;ld d, h ;ld e, l - + ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;dec c ;jp z, __ARRAY_FIN - + ;add hl, de - ;__ARRAY_FIN: -#line 131 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" - + ;__ARRAY_FIN: +#line 131 "/src/zxb/trunk/library-asm/array.asm" + pop de add hl, de ; Adds element start - + RET_ADDRESS: ld de, 0 push de ret ; HL = (Start of Elements + Offset) - + ;; Performs a faster multiply for little 16bit numbs LOCAL __FNMUL, __FNMUL2 - + __FNMUL: xor a or d jp nz, __MUL16_FAST - + or e ex de, hl ret z - + cp 33 jp nc, __MUL16_FAST - + ld b, l ld l, h ; HL = 0 - + __FNMUL2: add hl, de djnz __FNMUL2 ret - + ENDP - + #line 24 "array08.bas" #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -250,15 +250,15 @@ __FNMUL2: ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -266,25 +266,25 @@ __FNMUL2: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -293,52 +293,52 @@ __FNMUL2: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -346,12 +346,12 @@ __FNMUL2: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -359,7 +359,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -367,10 +367,10 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -378,25 +378,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -405,42 +405,42 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -448,25 +448,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -475,39 +475,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -515,57 +515,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -577,39 +577,39 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/src/zxbasic/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/src/zxbasic/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -617,15 +617,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -650,14 +650,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -665,25 +665,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 71 "realloc.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -691,25 +691,25 @@ __MEM_SUBTRACT: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -718,38 +718,38 @@ __MEM_SUBTRACT: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -758,57 +758,57 @@ __MEM_SUBTRACT: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -817,47 +817,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -867,12 +867,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 72 "realloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -891,29 +891,29 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -922,111 +922,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -1042,7 +1042,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -1050,44 +1050,44 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 25 "array08.bas" - + ZXBASIC_USER_DATA: _b: DEFB 00, 00 diff --git a/tests/functional/array09.asm b/tests/functional/array09.asm index a1da94d0d..a75bd3841 100644 --- a/tests/functional/array09.asm +++ b/tests/functional/array09.asm @@ -36,10 +36,10 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "array.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ------------------------------------------------------------------- ; Simple array Index routine @@ -47,28 +47,28 @@ __CALL_BACK__: ; HL = Start of array memory (First two bytes contains N-1 dimensions) ; Dimension values on the stack, (top of the stack, highest dimension) ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> - + ; For any array of N dimension A(aN-1, ..., a1, a0) ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] ; What I will do here is to calculate the following sequence: ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... - - + + #line 1 "mul16.asm" - + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned - + PROC - + LOCAL __MUL16LOOP LOCAL __MUL16NOADD - + ex de, hl pop hl ; Return address ex (sp), hl ; CALLEE caller convention - + ;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand ;; ld c, h ;; ld a, l ; C,A => 1st Operand @@ -86,44 +86,44 @@ __MUL16: ; Mutiplies HL with the last value stored into de stack ;;__MUL16NOADD: ;; sla e ;; rl d - ;; + ;; ;; djnz __MUL16LOOP - + __MUL16_FAST: ld b, 16 ld a, d ld c, e ex de, hl ld hl, 0 - + __MUL16LOOP: add hl, hl ; hl << 1 sla c rla ; a,c << 1 jp nc, __MUL16NOADD add hl, de - + __MUL16NOADD: djnz __MUL16LOOP - + ret ; Result in hl (16 lower bits) - + ENDP - + #line 20 "array.asm" - + #line 24 "/src/zxb/trunk/library-asm/array.asm" - + __ARRAY: PROC - + LOCAL LOOP LOCAL ARRAY_END LOCAL RET_ADDRESS ; Stores return address - + ex (sp), hl ; Return address in HL, array address in the stack ld (RET_ADDRESS + 1), hl ; Stores it for later - + exx pop hl ; Will use H'L' as the pointer ld c, (hl) ; Loads Number of dimensions from (hl) @@ -131,23 +131,23 @@ __ARRAY: ld b, (hl) inc hl ; Ready exx - + ld hl, 0 ; BC = Offset "accumulator" - + #line 48 "/src/zxb/trunk/library-asm/array.asm" - + LOOP: pop bc ; Get next index (Ai) from the stack - + #line 60 "/src/zxb/trunk/library-asm/array.asm" - + add hl, bc ; Adds current index - + exx ; Checks if B'C' = 0 ld a, b ; Which means we must exit (last element is not multiplied by anything) or c jr z, ARRAY_END ; if B'Ci == 0 we are done - + ld e, (hl) ; Loads next dimension into D'E' inc hl ld d, (hl) @@ -156,13 +156,13 @@ LOOP: dec bc ; Decrements loop counter exx pop de ; DE = Max bound Number (i-th dimension) - + #line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL #line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP - + ARRAY_END: ld e, (hl) inc hl @@ -170,76 +170,76 @@ ARRAY_END: push hl push de exx - + #line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP - + ex de, hl ld hl, 0 pop bc ld b, c -ARRAY_SIZE_LOOP: +ARRAY_SIZE_LOOP: add hl, de djnz ARRAY_SIZE_LOOP - + ;; Even faster ;pop bc - + ;ld d, h ;ld e, l - + ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;dec c ;jp z, __ARRAY_FIN - + ;add hl, de - ;__ARRAY_FIN: + ;__ARRAY_FIN: #line 131 "/src/zxb/trunk/library-asm/array.asm" - + pop de add hl, de ; Adds element start - + RET_ADDRESS: ld de, 0 push de ret ; HL = (Start of Elements + Offset) - + ;; Performs a faster multiply for little 16bit numbs LOCAL __FNMUL, __FNMUL2 - + __FNMUL: xor a or d jp nz, __MUL16_FAST - + or e ex de, hl ret z - + cp 33 jp nc, __MUL16_FAST - + ld b, l ld l, h ; HL = 0 - + __FNMUL2: add hl, de djnz __FNMUL2 ret - + ENDP - + #line 24 "array09.bas" #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -250,15 +250,15 @@ __FNMUL2: ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -266,25 +266,25 @@ __FNMUL2: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -293,52 +293,52 @@ __FNMUL2: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -346,12 +346,12 @@ __FNMUL2: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -359,7 +359,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -367,10 +367,10 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -378,25 +378,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -405,42 +405,42 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -448,25 +448,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -475,39 +475,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -515,57 +515,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -577,27 +577,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -609,7 +609,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -617,15 +617,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -650,14 +650,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -665,25 +665,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 71 "realloc.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -691,25 +691,25 @@ __MEM_SUBTRACT: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -718,38 +718,38 @@ __MEM_SUBTRACT: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -758,57 +758,57 @@ __MEM_SUBTRACT: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -817,47 +817,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -867,12 +867,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 72 "realloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -891,29 +891,29 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -922,111 +922,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -1042,7 +1042,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -1050,44 +1050,44 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 25 "array09.bas" - + ZXBASIC_USER_DATA: _b: DEFB 00, 00 diff --git a/tests/functional/array10.asm b/tests/functional/array10.asm index bf7d50aeb..b4575b4de 100644 --- a/tests/functional/array10.asm +++ b/tests/functional/array10.asm @@ -68,10 +68,10 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "array.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ------------------------------------------------------------------- ; Simple array Index routine @@ -79,28 +79,28 @@ __CALL_BACK__: ; HL = Start of array memory (First two bytes contains N-1 dimensions) ; Dimension values on the stack, (top of the stack, highest dimension) ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> - + ; For any array of N dimension A(aN-1, ..., a1, a0) ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] ; What I will do here is to calculate the following sequence: ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... - - + + #line 1 "mul16.asm" - + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned - + PROC - + LOCAL __MUL16LOOP LOCAL __MUL16NOADD - + ex de, hl pop hl ; Return address ex (sp), hl ; CALLEE caller convention - + ;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand ;; ld c, h ;; ld a, l ; C,A => 1st Operand @@ -118,44 +118,44 @@ __MUL16: ; Mutiplies HL with the last value stored into de stack ;;__MUL16NOADD: ;; sla e ;; rl d - ;; + ;; ;; djnz __MUL16LOOP - + __MUL16_FAST: ld b, 16 ld a, d ld c, e ex de, hl ld hl, 0 - + __MUL16LOOP: add hl, hl ; hl << 1 sla c rla ; a,c << 1 jp nc, __MUL16NOADD add hl, de - + __MUL16NOADD: djnz __MUL16LOOP - + ret ; Result in hl (16 lower bits) - + ENDP - + #line 20 "array.asm" - + #line 24 "/src/zxb/trunk/library-asm/array.asm" - + __ARRAY: PROC - + LOCAL LOOP LOCAL ARRAY_END LOCAL RET_ADDRESS ; Stores return address - + ex (sp), hl ; Return address in HL, array address in the stack ld (RET_ADDRESS + 1), hl ; Stores it for later - + exx pop hl ; Will use H'L' as the pointer ld c, (hl) ; Loads Number of dimensions from (hl) @@ -163,23 +163,23 @@ __ARRAY: ld b, (hl) inc hl ; Ready exx - + ld hl, 0 ; BC = Offset "accumulator" - + #line 48 "/src/zxb/trunk/library-asm/array.asm" - + LOOP: pop bc ; Get next index (Ai) from the stack - + #line 60 "/src/zxb/trunk/library-asm/array.asm" - + add hl, bc ; Adds current index - + exx ; Checks if B'C' = 0 ld a, b ; Which means we must exit (last element is not multiplied by anything) or c jr z, ARRAY_END ; if B'Ci == 0 we are done - + ld e, (hl) ; Loads next dimension into D'E' inc hl ld d, (hl) @@ -188,13 +188,13 @@ LOOP: dec bc ; Decrements loop counter exx pop de ; DE = Max bound Number (i-th dimension) - + #line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL #line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP - + ARRAY_END: ld e, (hl) inc hl @@ -202,75 +202,75 @@ ARRAY_END: push hl push de exx - + #line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP - + ex de, hl ld hl, 0 pop bc ld b, c -ARRAY_SIZE_LOOP: +ARRAY_SIZE_LOOP: add hl, de djnz ARRAY_SIZE_LOOP - + ;; Even faster ;pop bc - + ;ld d, h ;ld e, l - + ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;dec c ;jp z, __ARRAY_FIN - + ;add hl, de - ;__ARRAY_FIN: + ;__ARRAY_FIN: #line 131 "/src/zxb/trunk/library-asm/array.asm" - + pop de add hl, de ; Adds element start - + RET_ADDRESS: ld de, 0 push de ret ; HL = (Start of Elements + Offset) - + ;; Performs a faster multiply for little 16bit numbs LOCAL __FNMUL, __FNMUL2 - + __FNMUL: xor a or d jp nz, __MUL16_FAST - + or e ex de, hl ret z - + cp 33 jp nc, __MUL16_FAST - + ld b, l ld l, h ; HL = 0 - + __FNMUL2: add hl, de djnz __FNMUL2 ret - + ENDP - + #line 59 "array10.bas" - + ZXBASIC_USER_DATA: _tn: DEFB 00 diff --git a/tests/functional/array12.asm b/tests/functional/array12.asm index 7c1d70835..dd0225383 100644 --- a/tests/functional/array12.asm +++ b/tests/functional/array12.asm @@ -38,10 +38,10 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "array.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ------------------------------------------------------------------- ; Simple array Index routine @@ -49,28 +49,28 @@ __CALL_BACK__: ; HL = Start of array memory (First two bytes contains N-1 dimensions) ; Dimension values on the stack, (top of the stack, highest dimension) ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> - + ; For any array of N dimension A(aN-1, ..., a1, a0) ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] ; What I will do here is to calculate the following sequence: ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... - - + + #line 1 "mul16.asm" - + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned - + PROC - + LOCAL __MUL16LOOP LOCAL __MUL16NOADD - + ex de, hl pop hl ; Return address ex (sp), hl ; CALLEE caller convention - + ;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand ;; ld c, h ;; ld a, l ; C,A => 1st Operand @@ -88,44 +88,44 @@ __MUL16: ; Mutiplies HL with the last value stored into de stack ;;__MUL16NOADD: ;; sla e ;; rl d - ;; + ;; ;; djnz __MUL16LOOP - + __MUL16_FAST: ld b, 16 ld a, d ld c, e ex de, hl ld hl, 0 - + __MUL16LOOP: add hl, hl ; hl << 1 sla c rla ; a,c << 1 jp nc, __MUL16NOADD add hl, de - + __MUL16NOADD: djnz __MUL16LOOP - + ret ; Result in hl (16 lower bits) - + ENDP - + #line 20 "array.asm" - -#line 24 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" - + +#line 24 "/src/zxb/trunk/library-asm/array.asm" + __ARRAY: PROC - + LOCAL LOOP LOCAL ARRAY_END LOCAL RET_ADDRESS ; Stores return address - + ex (sp), hl ; Return address in HL, array address in the stack ld (RET_ADDRESS + 1), hl ; Stores it for later - + exx pop hl ; Will use H'L' as the pointer ld c, (hl) ; Loads Number of dimensions from (hl) @@ -133,23 +133,23 @@ __ARRAY: ld b, (hl) inc hl ; Ready exx - + ld hl, 0 ; BC = Offset "accumulator" - -#line 48 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" - + +#line 48 "/src/zxb/trunk/library-asm/array.asm" + LOOP: pop bc ; Get next index (Ai) from the stack - -#line 60 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" - + +#line 60 "/src/zxb/trunk/library-asm/array.asm" + add hl, bc ; Adds current index - + exx ; Checks if B'C' = 0 ld a, b ; Which means we must exit (last element is not multiplied by anything) or c jr z, ARRAY_END ; if B'Ci == 0 we are done - + ld e, (hl) ; Loads next dimension into D'E' inc hl ld d, (hl) @@ -158,13 +158,13 @@ LOOP: dec bc ; Decrements loop counter exx pop de ; DE = Max bound Number (i-th dimension) - -#line 80 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" + +#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" +#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP - + ARRAY_END: ld e, (hl) inc hl @@ -172,76 +172,76 @@ ARRAY_END: push hl push de exx - -#line 100 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" + +#line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP - + ex de, hl ld hl, 0 pop bc ld b, c -ARRAY_SIZE_LOOP: +ARRAY_SIZE_LOOP: add hl, de djnz ARRAY_SIZE_LOOP - + ;; Even faster ;pop bc - + ;ld d, h ;ld e, l - + ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;dec c ;jp z, __ARRAY_FIN - + ;add hl, de - ;__ARRAY_FIN: -#line 131 "/Users/boriel/src/zxbasic/zxbasic/library-asm/array.asm" - + ;__ARRAY_FIN: +#line 131 "/src/zxb/trunk/library-asm/array.asm" + pop de add hl, de ; Adds element start - + RET_ADDRESS: ld de, 0 push de ret ; HL = (Start of Elements + Offset) - + ;; Performs a faster multiply for little 16bit numbs LOCAL __FNMUL, __FNMUL2 - + __FNMUL: xor a or d jp nz, __MUL16_FAST - + or e ex de, hl ret z - + cp 33 jp nc, __MUL16_FAST - + ld b, l ld l, h ; HL = 0 - + __FNMUL2: add hl, de djnz __FNMUL2 ret - + ENDP - + #line 26 "array12.bas" #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -252,15 +252,15 @@ __FNMUL2: ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -268,25 +268,25 @@ __FNMUL2: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -295,52 +295,52 @@ __FNMUL2: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -348,12 +348,12 @@ __FNMUL2: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -361,7 +361,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -369,10 +369,10 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -380,25 +380,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -407,42 +407,42 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -450,25 +450,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -477,39 +477,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -517,57 +517,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -579,39 +579,39 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/Users/boriel/src/zxbasic/zxbasic/library-asm/alloc.asm" +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" ret z ; NULL -#line 113 "/Users/boriel/src/zxbasic/zxbasic/library-asm/alloc.asm" +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -619,15 +619,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -652,14 +652,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -667,25 +667,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 71 "realloc.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -693,25 +693,25 @@ __MEM_SUBTRACT: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -720,38 +720,38 @@ __MEM_SUBTRACT: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -760,57 +760,57 @@ __MEM_SUBTRACT: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -819,47 +819,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -869,12 +869,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 72 "realloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -893,29 +893,29 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -924,111 +924,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -1044,7 +1044,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -1052,44 +1052,44 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 27 "array12.bas" - + ZXBASIC_USER_DATA: _b: DEFB 00, 00 diff --git a/tests/functional/arraycopy0.asm b/tests/functional/arraycopy0.asm index 098d8c137..96b726098 100644 --- a/tests/functional/arraycopy0.asm +++ b/tests/functional/arraycopy0.asm @@ -40,7 +40,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/arraycopy1.asm b/tests/functional/arraycopy1.asm index 7414822de..b7bf1b8b6 100644 --- a/tests/functional/arraycopy1.asm +++ b/tests/functional/arraycopy1.asm @@ -62,7 +62,7 @@ _Test__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: _grid: DEFW 0000h diff --git a/tests/functional/arraycopy2.asm b/tests/functional/arraycopy2.asm index 9bcc04b2d..152faba4f 100644 --- a/tests/functional/arraycopy2.asm +++ b/tests/functional/arraycopy2.asm @@ -62,7 +62,7 @@ _Test__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: _gridcopy: DEFW 0000h diff --git a/tests/functional/arraycopy3.asm b/tests/functional/arraycopy3.asm index a8ea242e9..d5138b680 100644 --- a/tests/functional/arraycopy3.asm +++ b/tests/functional/arraycopy3.asm @@ -75,7 +75,7 @@ _Test__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: __LABEL0: DEFB 00h diff --git a/tests/functional/arrlabels.asm b/tests/functional/arrlabels.asm index c3e0ddb4e..9093ce1cb 100644 --- a/tests/functional/arrlabels.asm +++ b/tests/functional/arrlabels.asm @@ -34,7 +34,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFW 0000h diff --git a/tests/functional/arrlabels1.asm b/tests/functional/arrlabels1.asm index d3af099f3..b0400afaf 100644 --- a/tests/functional/arrlabels1.asm +++ b/tests/functional/arrlabels1.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFW 0000h diff --git a/tests/functional/arrlabels10a.asm b/tests/functional/arrlabels10a.asm index 1592484fa..96e2ca879 100644 --- a/tests/functional/arrlabels10a.asm +++ b/tests/functional/arrlabels10a.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFW 0000h diff --git a/tests/functional/arrlabels10b.asm b/tests/functional/arrlabels10b.asm index 9eb45276a..6a0a7cd4a 100644 --- a/tests/functional/arrlabels10b.asm +++ b/tests/functional/arrlabels10b.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFW 0000h diff --git a/tests/functional/arrlabels2.asm b/tests/functional/arrlabels2.asm index 54dd64753..cc8ddb589 100644 --- a/tests/functional/arrlabels2.asm +++ b/tests/functional/arrlabels2.asm @@ -31,7 +31,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFW 0000h diff --git a/tests/functional/arrlabels3.asm b/tests/functional/arrlabels3.asm index 46aa5c95c..2339ee11c 100644 --- a/tests/functional/arrlabels3.asm +++ b/tests/functional/arrlabels3.asm @@ -40,7 +40,7 @@ _f__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: _a: DEFW 0000h diff --git a/tests/functional/arrlabels4.asm b/tests/functional/arrlabels4.asm index 4ae827bee..d82ced2cb 100644 --- a/tests/functional/arrlabels4.asm +++ b/tests/functional/arrlabels4.asm @@ -61,7 +61,7 @@ _test__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: __LABEL0: DEFB 00h diff --git a/tests/functional/arrlabels5.asm b/tests/functional/arrlabels5.asm index c648c1399..4231f1a9d 100644 --- a/tests/functional/arrlabels5.asm +++ b/tests/functional/arrlabels5.asm @@ -61,7 +61,7 @@ _test__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: __LABEL0: DEFB 00h diff --git a/tests/functional/arrlabels6.asm b/tests/functional/arrlabels6.asm index 8d08c3f7f..8f12d6c78 100644 --- a/tests/functional/arrlabels6.asm +++ b/tests/functional/arrlabels6.asm @@ -34,7 +34,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFW 0000h diff --git a/tests/functional/arrlabels7.asm b/tests/functional/arrlabels7.asm index 6a2255a19..db4b8f6b1 100644 --- a/tests/functional/arrlabels7.asm +++ b/tests/functional/arrlabels7.asm @@ -61,7 +61,7 @@ _test__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: __LABEL0: DEFB 00h diff --git a/tests/functional/arrlabels8.asm b/tests/functional/arrlabels8.asm index 4ae827bee..d82ced2cb 100644 --- a/tests/functional/arrlabels8.asm +++ b/tests/functional/arrlabels8.asm @@ -61,7 +61,7 @@ _test__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: __LABEL0: DEFB 00h diff --git a/tests/functional/arrlabels9.asm b/tests/functional/arrlabels9.asm index 4ae827bee..d82ced2cb 100644 --- a/tests/functional/arrlabels9.asm +++ b/tests/functional/arrlabels9.asm @@ -61,7 +61,7 @@ _test__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: __LABEL0: DEFB 00h diff --git a/tests/functional/astore16.asm b/tests/functional/astore16.asm index d8998625a..85e4f0621 100644 --- a/tests/functional/astore16.asm +++ b/tests/functional/astore16.asm @@ -63,10 +63,10 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "array.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ------------------------------------------------------------------- ; Simple array Index routine @@ -74,28 +74,28 @@ __CALL_BACK__: ; HL = Start of array memory (First two bytes contains N-1 dimensions) ; Dimension values on the stack, (top of the stack, highest dimension) ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> - + ; For any array of N dimension A(aN-1, ..., a1, a0) ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] ; What I will do here is to calculate the following sequence: ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... - - + + #line 1 "mul16.asm" - + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned - + PROC - + LOCAL __MUL16LOOP LOCAL __MUL16NOADD - + ex de, hl pop hl ; Return address ex (sp), hl ; CALLEE caller convention - + ;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand ;; ld c, h ;; ld a, l ; C,A => 1st Operand @@ -113,44 +113,44 @@ __MUL16: ; Mutiplies HL with the last value stored into de stack ;;__MUL16NOADD: ;; sla e ;; rl d - ;; + ;; ;; djnz __MUL16LOOP - + __MUL16_FAST: ld b, 16 ld a, d ld c, e ex de, hl ld hl, 0 - + __MUL16LOOP: add hl, hl ; hl << 1 sla c rla ; a,c << 1 jp nc, __MUL16NOADD add hl, de - + __MUL16NOADD: djnz __MUL16LOOP - + ret ; Result in hl (16 lower bits) - + ENDP - + #line 20 "array.asm" - + #line 24 "/src/zxb/trunk/library-asm/array.asm" - + __ARRAY: PROC - + LOCAL LOOP LOCAL ARRAY_END LOCAL RET_ADDRESS ; Stores return address - + ex (sp), hl ; Return address in HL, array address in the stack ld (RET_ADDRESS + 1), hl ; Stores it for later - + exx pop hl ; Will use H'L' as the pointer ld c, (hl) ; Loads Number of dimensions from (hl) @@ -158,23 +158,23 @@ __ARRAY: ld b, (hl) inc hl ; Ready exx - + ld hl, 0 ; BC = Offset "accumulator" - + #line 48 "/src/zxb/trunk/library-asm/array.asm" - + LOOP: pop bc ; Get next index (Ai) from the stack - + #line 60 "/src/zxb/trunk/library-asm/array.asm" - + add hl, bc ; Adds current index - + exx ; Checks if B'C' = 0 ld a, b ; Which means we must exit (last element is not multiplied by anything) or c jr z, ARRAY_END ; if B'Ci == 0 we are done - + ld e, (hl) ; Loads next dimension into D'E' inc hl ld d, (hl) @@ -183,13 +183,13 @@ LOOP: dec bc ; Decrements loop counter exx pop de ; DE = Max bound Number (i-th dimension) - + #line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL #line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP - + ARRAY_END: ld e, (hl) inc hl @@ -197,86 +197,86 @@ ARRAY_END: push hl push de exx - + #line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP - + ex de, hl ld hl, 0 pop bc ld b, c -ARRAY_SIZE_LOOP: +ARRAY_SIZE_LOOP: add hl, de djnz ARRAY_SIZE_LOOP - + ;; Even faster ;pop bc - + ;ld d, h ;ld e, l - + ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;dec c ;jp z, __ARRAY_FIN - + ;add hl, de - ;__ARRAY_FIN: + ;__ARRAY_FIN: #line 131 "/src/zxb/trunk/library-asm/array.asm" - + pop de add hl, de ; Adds element start - + RET_ADDRESS: ld de, 0 push de ret ; HL = (Start of Elements + Offset) - + ;; Performs a faster multiply for little 16bit numbs LOCAL __FNMUL, __FNMUL2 - + __FNMUL: xor a or d jp nz, __MUL16_FAST - + or e ex de, hl ret z - + cp 33 jp nc, __MUL16_FAST - + ld b, l ld l, h ; HL = 0 - + __FNMUL2: add hl, de djnz __FNMUL2 ret - + ENDP - + #line 53 "astore16.bas" #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -284,46 +284,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -336,43 +336,43 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -380,12 +380,12 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -393,51 +393,51 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "in_screen.asm" - + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -446,17 +446,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -464,26 +464,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -497,45 +497,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -546,28 +546,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -575,28 +575,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -605,83 +605,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -690,32 +690,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -725,7 +725,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -733,20 +733,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -756,7 +756,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -767,19 +767,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -789,7 +789,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -800,19 +800,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -822,7 +822,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -835,22 +835,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -859,79 +859,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -940,75 +940,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -1018,7 +1018,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -1030,16 +1030,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1053,49 +1053,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1106,17 +1106,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1129,27 +1129,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1157,10 +1157,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1177,80 +1177,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1267,8 +1267,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1292,17 +1292,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1313,7 +1313,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1323,21 +1323,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1356,9 +1356,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1383,33 +1383,33 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 54 "astore16.bas" #line 1 "printu16.asm" - + #line 1 "printi16.asm" - + #line 1 "printnum.asm" - - - - + + + + __PRINTU_START: PROC - + LOCAL __PRINTU_CONT - + ld a, b or a jp nz, __PRINTU_CONT - + ld a, '0' jp __PRINT_DIGIT - - + + __PRINTU_CONT: pop af push bc @@ -1417,30 +1417,30 @@ __PRINTU_CONT: pop bc djnz __PRINTU_CONT ret - + ENDP - - + + __PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers ld a, '-' jp __PRINT_DIGIT - + __PRINT_DIGIT EQU __PRINTCHAR ; PRINTS the char in A register, and puts its attrs - - + + #line 2 "printi16.asm" #line 1 "div16.asm" - - ; 16 bit division and modulo functions + + ; 16 bit division and modulo functions ; for both signed and unsigned values - + #line 1 "neg16.asm" - + ; Negates HL value (16 bit) __ABS16: bit 7, h ret z - + __NEGHL: ld a, l ; HL = -HL cpl @@ -1450,23 +1450,23 @@ __NEGHL: ld h, a inc hl ret - + #line 5 "div16.asm" - + __DIVU16: ; 16 bit unsigned division ; HL = Dividend, Stack Top = Divisor - + ; -- OBSOLETE ; Now uses FASTCALL convention ; ex de, hl ; pop hl ; Return address ; ex (sp), hl ; CALLEE Convention - + __DIVU16_FAST: ld a, h ld c, l ld hl, 0 ld b, 16 - + __DIV16LOOP: sll c rla @@ -1475,46 +1475,46 @@ __DIV16LOOP: jr nc, __DIV16NOADD add hl,de dec c - + __DIV16NOADD: djnz __DIV16LOOP - + ex de, hl ld h, a ld l, c - + ret ; HL = quotient, DE = Mudulus - - - + + + __MODU16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVU16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - - + + __DIVI16: ; 16 bit signed division ; --- The following is OBSOLETE --- ; ex de, hl ; pop hl ; ex (sp), hl ; CALLEE Convention - + __DIVI16_FAST: ld a, d xor h ex af, af' ; BIT 7 of a contains result - + bit 7, d ; DE is negative? - jr z, __DIVI16A - + jr z, __DIVI16A + ld a, e ; DE = -DE cpl ld e, a @@ -1522,75 +1522,75 @@ __DIVI16_FAST: cpl ld d, a inc de - + __DIVI16A: bit 7, h ; HL is negative? call nz, __NEGHL - + __DIVI16B: call __DIVU16_FAST ex af, af' - - or a + + or a ret p ; return if positive jp __NEGHL - - + + __MODI16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVI16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - + #line 3 "printi16.asm" - - - + + + __PRINTI16: ; Prints a 16bits signed in HL ; Converts 16 to 32 bits PROC - + LOCAL __PRINTU_LOOP ld a, h or a - + jp p, __PRINTU16 - + call __PRINT_MINUS call __NEGHL - + __PRINTU16: - + ld b, 0 __PRINTU_LOOP: ld a, h or l jp z, __PRINTU_START - + push bc ld de, 10 call __DIVU16_FAST ; Divides by DE. DE = MODULUS at exit. Since < 256, E = Modulus pop bc - + ld a, e or '0' ; Stores ASCII digit (must be print in reversed order) push af inc b jp __PRINTU_LOOP ; Uses JP in loops - + ENDP - + #line 2 "printu16.asm" - + #line 55 "astore16.bas" - + ZXBASIC_USER_DATA: _i: DEFB 00 diff --git a/tests/functional/ataddr.asm b/tests/functional/ataddr.asm index 59e3a2856..85167e629 100644 --- a/tests/functional/ataddr.asm +++ b/tests/functional/ataddr.asm @@ -30,7 +30,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _b: DEFB 00, 00 diff --git a/tests/functional/atfunc0.asm b/tests/functional/atfunc0.asm index c26dd2d67..1138a606a 100644 --- a/tests/functional/atfunc0.asm +++ b/tests/functional/atfunc0.asm @@ -36,7 +36,7 @@ _myfunc__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/atfunc1.asm b/tests/functional/atfunc1.asm index c26dd2d67..1138a606a 100644 --- a/tests/functional/atfunc1.asm +++ b/tests/functional/atfunc1.asm @@ -36,7 +36,7 @@ _myfunc__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/atlabel.asm b/tests/functional/atlabel.asm index ebad8613c..9d44a7668 100644 --- a/tests/functional/atlabel.asm +++ b/tests/functional/atlabel.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _radians: _a: diff --git a/tests/functional/atlabel1.asm b/tests/functional/atlabel1.asm index cd16cb67b..665122fe4 100644 --- a/tests/functional/atlabel1.asm +++ b/tests/functional/atlabel1.asm @@ -34,7 +34,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "storef.asm" - + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -42,7 +42,7 @@ __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory pop hl ; HL <- IX add hl, de ; HL <- IX + HL pop de - + __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register ex af, af' ld a, (hl) @@ -50,7 +50,7 @@ __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address ld h, (hl) ld l, a ; HL = (HL) ex af, af' - + __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), a inc hl @@ -62,9 +62,9 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL inc hl ld (hl), b ret - + #line 25 "atlabel1.bas" - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/atlabel2.asm b/tests/functional/atlabel2.asm index 522be4ea1..646bfb4b5 100644 --- a/tests/functional/atlabel2.asm +++ b/tests/functional/atlabel2.asm @@ -40,7 +40,7 @@ _test__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/atlabel3.asm b/tests/functional/atlabel3.asm index 2a2c6de76..b19fdadd5 100644 --- a/tests/functional/atlabel3.asm +++ b/tests/functional/atlabel3.asm @@ -48,7 +48,7 @@ _test2__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/attr.asm b/tests/functional/attr.asm index 01a58f42a..fb6490f9e 100644 --- a/tests/functional/attr.asm +++ b/tests/functional/attr.asm @@ -42,17 +42,17 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register #line 1 "copy_attr.asm" - + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -60,35 +60,35 @@ __CALL_BACK__: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 6 "copy_attr.asm" - + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - + #line 63 "/src/zxb/trunk/library-asm/copy_attr.asm" ret #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -97,14 +97,14 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "bold.asm" - + BOLD: PROC - + and 1 rlca rlca @@ -114,7 +114,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -125,24 +125,24 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 33 "attr.bas" - + #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -150,38 +150,38 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 35 "attr.bas" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -195,42 +195,42 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 36 "attr.bas" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register - - - + + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -240,7 +240,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -248,40 +248,40 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 37 "attr.bas" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -292,16 +292,16 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 38 "attr.bas" - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/band16.asm b/tests/functional/band16.asm index 85ad5ef50..adff84e28 100644 --- a/tests/functional/band16.asm +++ b/tests/functional/band16.asm @@ -56,28 +56,28 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "band16.asm" - + ; vim:ts=4:et: ; FASTCALL bitwise and16 version. - ; result in hl + ; result in hl ; __FASTCALL__ version (operands: A, H) ; Performs 16bit or 16bit and returns the boolean ; Input: HL, DE ; Output: HL <- HL AND DE - + __BAND16: ld a, h and d ld h, a - + ld a, l and e ld l, a - - ret - + + ret + #line 47 "band16.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/band32.asm b/tests/functional/band32.asm index 5a1529974..0c4bb8869 100644 --- a/tests/functional/band32.asm +++ b/tests/functional/band32.asm @@ -90,45 +90,45 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "band32.asm" - + ; FASTCALL bitwise and 32 version. ; Performs 32bit and 32bit and returns the bitwise ; result in DE,HL ; First operand in DE,HL 2nd operand into the stack - + __BAND32: ld b, h ld c, l ; BC <- HL - + pop hl ; Return address ex (sp), hl ; HL <- Lower part of 2nd Operand - + ld a, b and h ld b, a - + ld a, c and l ld c, a ; BC <- BC & HL - + pop hl ; Return dddress ex (sp), hl ; HL <- High part of 2nd Operand - + ld a, d and h ld d, a - + ld a, e and l ld e, a ; DE <- DE & HL - + ld h, b ld l, c ; HL <- BC ; Always return DE,HL pair regs - + ret - + #line 81 "band32.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00 diff --git a/tests/functional/band8.asm b/tests/functional/band8.asm index c37f7afd6..0f5061301 100644 --- a/tests/functional/band8.asm +++ b/tests/functional/band8.asm @@ -55,20 +55,20 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "and8.asm" - + ; FASTCALL boolean and 8 version. ; result in Accumulator (0 False, not 0 True) ; __FASTCALL__ version (operands: A, H) ; Performs 8bit and 8bit and returns the boolean - + __AND8: or a ret z ld a, h - ret - + ret + #line 46 "band8.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/bin00.asm b/tests/functional/bin00.asm index 2f44c47cb..f106cb8c4 100644 --- a/tests/functional/bin00.asm +++ b/tests/functional/bin00.asm @@ -30,7 +30,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _c: DEFB 00 diff --git a/tests/functional/bitwise.asm b/tests/functional/bitwise.asm index b4d157f13..18ea78b7e 100644 --- a/tests/functional/bitwise.asm +++ b/tests/functional/bitwise.asm @@ -42,20 +42,20 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "and8.asm" - + ; FASTCALL boolean and 8 version. ; result in Accumulator (0 False, not 0 True) ; __FASTCALL__ version (operands: A, H) ; Performs 8bit and 8bit and returns the boolean - + __AND8: or a ret z ld a, h - ret - + ret + #line 33 "bitwise.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/bnot16.asm b/tests/functional/bnot16.asm index c7bfe2440..9bc963536 100644 --- a/tests/functional/bnot16.asm +++ b/tests/functional/bnot16.asm @@ -38,28 +38,28 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "bnot16.asm" - + ; vim:ts=4:et: ; FASTCALL bitwise or 16 version. ; result in HL ; __FASTCALL__ version (operands: A, H) ; Performs 16bit NEGATION ; Input: HL -; Output: HL <- NOT HL - +; Output: HL <- NOT HL + __BNOT16: ld a, h cpl ld h, a - + ld a, l cpl ld l, a - - ret - + + ret + #line 29 "bnot16.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/bor16.asm b/tests/functional/bor16.asm index 1b76a006d..5b74fdfe4 100644 --- a/tests/functional/bor16.asm +++ b/tests/functional/bor16.asm @@ -56,7 +56,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "bor16.asm" - + ; vim:ts=4:et: ; FASTCALL bitwise or 16 version. ; result in HL @@ -64,20 +64,20 @@ __CALL_BACK__: ; Performs 16bit or 16bit and returns the boolean ; Input: HL, DE ; Output: HL <- HL OR DE - + __BOR16: ld a, h or d ld h, a - + ld a, l or e ld l, a - - ret - + + ret + #line 47 "bor16.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/bor32.asm b/tests/functional/bor32.asm index c4477f02c..bb478fa08 100644 --- a/tests/functional/bor32.asm +++ b/tests/functional/bor32.asm @@ -90,45 +90,45 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "bor32.asm" - + ; FASTCALL bitwise or 32 version. ; Performs 32bit or 32bit and returns the bitwise ; result DE,HL ; First operand in DE,HL 2nd operand into the stack - + __BOR32: ld b, h ld c, l ; BC <- HL - + pop hl ; Return address ex (sp), hl ; HL <- Lower part of 2nd Operand - + ld a, b or h ld b, a - + ld a, c or l ld c, a ; BC <- BC & HL - + pop hl ; Return dddress ex (sp), hl ; HL <- High part of 2nd Operand - + ld a, d or h ld d, a - + ld a, e or l ld e, a ; DE <- DE & HL - + ld h, b ld l, c ; HL <- BC ; Always return DE,HL pair regs - + ret - + #line 81 "bor32.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00 diff --git a/tests/functional/bor8.asm b/tests/functional/bor8.asm index 3dcc678d5..7471a4190 100644 --- a/tests/functional/bor8.asm +++ b/tests/functional/bor8.asm @@ -48,7 +48,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/bound00.asm b/tests/functional/bound00.asm index 68ff1b7f6..aef38d819 100644 --- a/tests/functional/bound00.asm +++ b/tests/functional/bound00.asm @@ -30,7 +30,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _b: DEFB 00, 00 diff --git a/tests/functional/bound01.asm b/tests/functional/bound01.asm index 8b5a86863..bfcdd8493 100644 --- a/tests/functional/bound01.asm +++ b/tests/functional/bound01.asm @@ -34,7 +34,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _b: DEFB 00, 00 diff --git a/tests/functional/bound02.asm b/tests/functional/bound02.asm index be2edcbff..ae10931b4 100644 --- a/tests/functional/bound02.asm +++ b/tests/functional/bound02.asm @@ -52,38 +52,38 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "bound.asm" - + ; --------------------------------------------------------- ; Copyleft (k)2011 by Jose Rodriguez (a.k.a. Boriel) -; http://www.boriel.com +; http://www.boriel.com ; ; ZX BASIC Compiler http://www.zxbasic.net ; This code is released under the BSD License ; --------------------------------------------------------- - + ; Implements bothe the LBOUND(array, N) and RBOUND(array, N) function - + ; Parameters: ; HL = N (dimension) ; [stack - 2] -> LBound table for the var ; Returns entry [N] in HL - + __BOUND: add hl, hl ; hl *= 2 ex de, hl pop hl ex (sp), hl ; __CALLEE - + add hl, de ; hl += OFFSET __LBOUND._xxxx ld e, (hl) ; de = (hl) inc hl ld d, (hl) - + ex de, hl ; hl = de => returns result in HL ret - + #line 43 "bound02.bas" - + ZXBASIC_USER_DATA: _b: DEFB 00 diff --git a/tests/functional/bound03.asm b/tests/functional/bound03.asm index a964fce16..fa79cd92b 100644 --- a/tests/functional/bound03.asm +++ b/tests/functional/bound03.asm @@ -52,38 +52,38 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "bound.asm" - + ; --------------------------------------------------------- ; Copyleft (k)2011 by Jose Rodriguez (a.k.a. Boriel) -; http://www.boriel.com +; http://www.boriel.com ; ; ZX BASIC Compiler http://www.zxbasic.net ; This code is released under the BSD License ; --------------------------------------------------------- - + ; Implements bothe the LBOUND(array, N) and RBOUND(array, N) function - + ; Parameters: ; HL = N (dimension) ; [stack - 2] -> LBound table for the var ; Returns entry [N] in HL - + __BOUND: add hl, hl ; hl *= 2 ex de, hl pop hl ex (sp), hl ; __CALLEE - + add hl, de ; hl += OFFSET __LBOUND._xxxx ld e, (hl) ; de = (hl) inc hl ld d, (hl) - + ex de, hl ; hl = de => returns result in HL ret - + #line 43 "bound03.bas" - + ZXBASIC_USER_DATA: _b: DEFB 00 diff --git a/tests/functional/bound04.asm b/tests/functional/bound04.asm index f64ebf76e..73c614097 100644 --- a/tests/functional/bound04.asm +++ b/tests/functional/bound04.asm @@ -30,7 +30,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _c: DEFB 00, 00 diff --git a/tests/functional/britlion0.asm b/tests/functional/britlion0.asm index 6e4797400..43b68f937 100644 --- a/tests/functional/britlion0.asm +++ b/tests/functional/britlion0.asm @@ -30,7 +30,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _num: DEFB 00, 00, 00, 00 diff --git a/tests/functional/bxor16.asm b/tests/functional/bxor16.asm index 8c8243946..da9d2da7d 100644 --- a/tests/functional/bxor16.asm +++ b/tests/functional/bxor16.asm @@ -56,7 +56,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "bxor16.asm" - + ; vim:ts=4:et: ; FASTCALL bitwise xor 16 version. ; result in Accumulator (0 False, not 0 True) @@ -64,26 +64,26 @@ __CALL_BACK__: ; Performs 16bit xor 16bit and returns the boolean ; Input: HL, DE ; Output: HL <- HL XOR DE - + __BXOR16: ld a, h xor d ld h, a - + ld a, l xor e ld l, a - - ret - + + ret + #line 47 "bxor16.bas" #line 1 "neg16.asm" - + ; Negates HL value (16 bit) __ABS16: bit 7, h ret z - + __NEGHL: ld a, l ; HL = -HL cpl @@ -93,9 +93,9 @@ __NEGHL: ld h, a inc hl ret - + #line 48 "bxor16.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/bxor32.asm b/tests/functional/bxor32.asm index 95e767a31..ef498c650 100644 --- a/tests/functional/bxor32.asm +++ b/tests/functional/bxor32.asm @@ -90,45 +90,45 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "bxor32.asm" - + ; FASTCALL bitwise xor 32 version. ; Performs 32bit xor 32bit and returns the bitwise ; result DE,HL ; First operand in DE,HL 2nd operand into the stack - + __BXOR32: ld b, h ld c, l ; BC <- HL - + pop hl ; Return address ex (sp), hl ; HL <- Lower part of 2nd Operand - + ld a, b xor h ld b, a - + ld a, c xor l ld c, a ; BC <- BC & HL - + pop hl ; Return dddress ex (sp), hl ; HL <- High part of 2nd Operand - + ld a, d xor h ld d, a - + ld a, e xor l ld e, a ; DE <- DE & HL - + ld h, b ld l, c ; HL <- BC ; Always return DE,HL pair regs - + ret - + #line 81 "bxor32.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00 diff --git a/tests/functional/bxor8.asm b/tests/functional/bxor8.asm index b902d78b2..d0acae34d 100644 --- a/tests/functional/bxor8.asm +++ b/tests/functional/bxor8.asm @@ -48,7 +48,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/byref32.asm b/tests/functional/byref32.asm index caa8894ef..4a8ed8fd1 100644 --- a/tests/functional/byref32.asm +++ b/tests/functional/byref32.asm @@ -61,14 +61,14 @@ _test__leave: exx ret #line 1 "iload32.asm" - + ; __FASTCALL__ routine which ; loads a 32 bits integer into DE,HL ; stored at position pointed by POINTER HL ; DE,HL <-- (HL) - + __ILOAD32: - ld e, (hl) + ld e, (hl) inc hl ld d, (hl) inc hl @@ -78,25 +78,25 @@ __ILOAD32: ld l, a ex de, hl ret - + #line 52 "byref32.bas" #line 1 "pistore32.asm" - + #line 1 "store32.asm" - + __PISTORE32: push hl push ix pop hl add hl, bc pop bc - + __ISTORE32: ; Load address at hl, and stores E,D,B,C integer at that address ld a, (hl) inc hl ld h, (hl) ld l, a - + __STORE32: ; Stores the given integer in DEBC at address HL ld (hl), c inc hl @@ -106,12 +106,12 @@ __STORE32: ; Stores the given integer in DEBC at address HL inc hl ld (hl), d ret - + #line 2 "pistore32.asm" - + ; The content of this file has been moved to "store32.asm" #line 53 "byref32.bas" - + ZXBASIC_USER_DATA: _y: DEFB 00, 00, 00, 00 diff --git a/tests/functional/byte_neq.asm b/tests/functional/byte_neq.asm index 2b920a002..9842453a7 100644 --- a/tests/functional/byte_neq.asm +++ b/tests/functional/byte_neq.asm @@ -33,7 +33,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/byval32.asm b/tests/functional/byval32.asm index 025a7262e..027abe821 100644 --- a/tests/functional/byval32.asm +++ b/tests/functional/byval32.asm @@ -63,22 +63,22 @@ _test__leave: exx ret #line 1 "pstore32.asm" - + #line 1 "store32.asm" - + __PISTORE32: push hl push ix pop hl add hl, bc pop bc - + __ISTORE32: ; Load address at hl, and stores E,D,B,C integer at that address ld a, (hl) inc hl ld h, (hl) ld l, a - + __STORE32: ; Stores the given integer in DEBC at address HL ld (hl), c inc hl @@ -88,9 +88,9 @@ __STORE32: ; Stores the given integer in DEBC at address HL inc hl ld (hl), d ret - + #line 2 "pstore32.asm" - + ; Stores a 32 bit integer number (DE,HL) at (IX + BC) __PSTORE32: push hl @@ -100,7 +100,7 @@ __PSTORE32: pop bc jp __STORE32 #line 54 "byval32.bas" - + ZXBASIC_USER_DATA: _y: DEFB 00, 00, 00, 00 diff --git a/tests/functional/castF16toF.asm b/tests/functional/castF16toF.asm index 95544ca4d..1deb6dc9f 100644 --- a/tests/functional/castF16toF.asm +++ b/tests/functional/castF16toF.asm @@ -32,43 +32,43 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "f16tofreg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "f16tofreg.asm" #line 1 "u32tofreg.asm" - - + + __I8TOFREG: ld l, a rlca @@ -76,35 +76,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -112,20 +112,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -133,53 +133,53 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 3 "f16tofreg.asm" - + __F16TOFREG: ; Converts a 16.16 signed fixed point (stored in DEHL) ; to a Floating Point Number returned in (C ED CB) PROC - + LOCAL __F16TOFREG2 - + ld a, d or a ; Test sign - + jp p, __F16TOFREG2 ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __F16TOFREG2 ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - - + + __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in C DE HL - + ld a, d or e or h @@ -187,26 +187,26 @@ __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ld b, h ld c, l ret z ; Return 00 0000 0000 if 0 - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 112 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c jp __U32TOFREG_LOOP ; Proceed as an integer - + ENDP - + #line 23 "castF16toF.bas" #line 1 "storef.asm" - + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -214,7 +214,7 @@ __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory pop hl ; HL <- IX add hl, de ; HL <- IX + HL pop de - + __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register ex af, af' ld a, (hl) @@ -222,7 +222,7 @@ __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address ld h, (hl) ld l, a ; HL = (HL) ex af, af' - + __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), a inc hl @@ -234,9 +234,9 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL inc hl ld (hl), b ret - + #line 24 "castF16toF.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00h diff --git a/tests/functional/chr.asm b/tests/functional/chr.asm index ee1fde6fc..f519ef983 100644 --- a/tests/functional/chr.asm +++ b/tests/functional/chr.asm @@ -44,15 +44,15 @@ __LABEL0: DEFW 0001h DEFB 21h #line 1 "chr.asm" - + ; CHR$(x, y, x) returns the string CHR$(x) + CHR$(y) + CHR$(z) ; - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -60,25 +60,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -87,51 +87,51 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -139,12 +139,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -152,7 +152,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -160,10 +160,10 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -171,25 +171,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -198,39 +198,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -238,57 +238,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -300,27 +300,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -332,7 +332,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -340,15 +340,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -373,14 +373,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -388,94 +388,94 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 5 "chr.asm" - + CHR: ; Returns HL = Pointer to STRING (NULL if no memory) ; Requires alloc.asm for dynamic memory heap. ; Parameters: HL = Number of bytes to insert (already push onto the stack) ; STACK => parameters (16 bit, only the High byte is considered) ; Used registers A, A', BC, DE, HL, H'L' - + PROC - + LOCAL __POPOUT LOCAL TMP - + TMP EQU 23629 ; (DEST System variable) - + ld a, h or l ret z ; If Number of parameters is ZERO, return NULL STRING - + ld b, h ld c, l - + pop hl ; Return address ld (TMP), hl - + push bc inc bc inc bc ; BC = BC + 2 => (2 bytes for the length number) call __MEM_ALLOC pop bc - + ld d, h ld e, l ; Saves HL in DE - + ld a, h or l jr z, __POPOUT ; No Memory, return - + ld (hl), c inc hl ld (hl), b inc hl - + __POPOUT: ; Removes out of the stack every byte and return ; If Zero Flag is set, don't store bytes in memory - ex af, af' ; Save Zero Flag - + ex af, af' ; Save Zero Flag + ld a, b or c jr z, __CHR_END - + dec bc pop af ; Next byte - + ex af, af' ; Recovers Zero flag jr z, __POPOUT - + ex af, af' ; Saves Zero flag ld (hl), a inc hl ex af, af' ; Recovers Zero Flag - + jp __POPOUT - + __CHR_END: ld hl, (TMP) push hl ; Restores return addr ex de, hl ; Recovers original HL ptr ret - + ENDP - + #line 32 "chr.bas" #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -486,15 +486,15 @@ __CHR_END: ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -502,25 +502,25 @@ __CHR_END: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -529,44 +529,44 @@ __CHR_END: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -574,25 +574,25 @@ __CHR_END: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -601,38 +601,38 @@ __CHR_END: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -641,57 +641,57 @@ __CHR_END: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -700,47 +700,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -750,12 +750,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 72 "realloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -774,29 +774,29 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -805,111 +805,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -925,7 +925,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -933,86 +933,86 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 33 "chr.bas" #line 1 "storestr2.asm" - + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication ; HL = address of string memory variable ; DE = address of 2n string. It just copies DE into (HL) ; freeing (HL) previously. - - - + + + __PISTORE_STR2: ; Indirect store temporary string at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR2: ld c, (hl) ; Dereferences HL inc hl ld h, (hl) ld l, c ; HL = *HL (real string variable address) - + __STORE_STR2: push hl ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = *HL (real string address) - + push de call __MEM_FREE pop de - + pop hl ld (hl), e inc hl ld (hl), d dec hl ; HL points to mem address variable. This might be useful in the future. - + ret - + #line 34 "chr.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/chr0.asm b/tests/functional/chr0.asm index 2e882e1a6..f9da653ba 100644 --- a/tests/functional/chr0.asm +++ b/tests/functional/chr0.asm @@ -43,15 +43,15 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "chr.asm" - + ; CHR$(x, y, x) returns the string CHR$(x) + CHR$(y) + CHR$(z) ; - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -59,25 +59,25 @@ __CALL_BACK__: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -86,51 +86,51 @@ __CALL_BACK__: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -138,12 +138,12 @@ __CALL_BACK__: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -151,7 +151,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -159,10 +159,10 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -170,25 +170,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -197,39 +197,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -237,57 +237,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -299,27 +299,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -331,7 +331,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -339,15 +339,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -372,14 +372,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -387,106 +387,106 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 5 "chr.asm" - + CHR: ; Returns HL = Pointer to STRING (NULL if no memory) ; Requires alloc.asm for dynamic memory heap. ; Parameters: HL = Number of bytes to insert (already push onto the stack) ; STACK => parameters (16 bit, only the High byte is considered) ; Used registers A, A', BC, DE, HL, H'L' - + PROC - + LOCAL __POPOUT LOCAL TMP - + TMP EQU 23629 ; (DEST System variable) - + ld a, h or l ret z ; If Number of parameters is ZERO, return NULL STRING - + ld b, h ld c, l - + pop hl ; Return address ld (TMP), hl - + push bc inc bc inc bc ; BC = BC + 2 => (2 bytes for the length number) call __MEM_ALLOC pop bc - + ld d, h ld e, l ; Saves HL in DE - + ld a, h or l jr z, __POPOUT ; No Memory, return - + ld (hl), c inc hl ld (hl), b inc hl - + __POPOUT: ; Removes out of the stack every byte and return ; If Zero Flag is set, don't store bytes in memory - ex af, af' ; Save Zero Flag - + ex af, af' ; Save Zero Flag + ld a, b or c jr z, __CHR_END - + dec bc pop af ; Next byte - + ex af, af' ; Recovers Zero flag jr z, __POPOUT - + ex af, af' ; Saves Zero flag ld (hl), a inc hl ex af, af' ; Recovers Zero Flag - + jp __POPOUT - + __CHR_END: ld hl, (TMP) push hl ; Restores return addr ex de, hl ; Recovers original HL ptr ret - + ENDP - + #line 31 "chr0.bas" #line 1 "storestr2.asm" - + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication ; HL = address of string memory variable ; DE = address of 2n string. It just copies DE into (HL) ; freeing (HL) previously. - + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -494,25 +494,25 @@ __CHR_END: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -521,38 +521,38 @@ __CHR_END: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -561,57 +561,57 @@ __CHR_END: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -620,47 +620,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -670,43 +670,43 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 9 "storestr2.asm" - + __PISTORE_STR2: ; Indirect store temporary string at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR2: ld c, (hl) ; Dereferences HL inc hl ld h, (hl) ld l, c ; HL = *HL (real string variable address) - + __STORE_STR2: push hl ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = *HL (real string address) - + push de call __MEM_FREE pop de - + pop hl ld (hl), e inc hl ld (hl), d dec hl ; HL points to mem address variable. This might be useful in the future. - + ret - + #line 32 "chr0.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/chr1.asm b/tests/functional/chr1.asm index e8aceb2b1..46ab1fa00 100644 --- a/tests/functional/chr1.asm +++ b/tests/functional/chr1.asm @@ -38,7 +38,7 @@ __LABEL0: DEFB 41h DEFB 21h #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -49,15 +49,15 @@ __LABEL0: ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -65,25 +65,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -92,52 +92,52 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -145,12 +145,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -158,7 +158,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -166,10 +166,10 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -177,25 +177,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -204,42 +204,42 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -247,25 +247,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -274,39 +274,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -314,57 +314,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -376,27 +376,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -408,7 +408,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -416,15 +416,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -449,14 +449,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -464,25 +464,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 71 "realloc.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -490,25 +490,25 @@ __MEM_SUBTRACT: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -517,38 +517,38 @@ __MEM_SUBTRACT: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -557,57 +557,57 @@ __MEM_SUBTRACT: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -616,47 +616,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -666,12 +666,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 72 "realloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -690,29 +690,29 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -721,111 +721,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -841,7 +841,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -849,44 +849,44 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 26 "chr1.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/circle.asm b/tests/functional/circle.asm index 34d50b9f0..04eb3df30 100644 --- a/tests/functional/circle.asm +++ b/tests/functional/circle.asm @@ -85,25 +85,25 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "circle.asm" - + ; Bresenham's like circle algorithm ; best known as Middle Point Circle drawing algorithm - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -111,12 +111,12 @@ __CALL_BACK__: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -124,7 +124,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -132,22 +132,22 @@ __STOP: ret #line 5 "circle.asm" #line 1 "plot.asm" - + ; MIXED __FASTCAL__ / __CALLE__ PLOT Function ; Plots a point into the screen calling the ZX ROM PLOT routine - + ; Y in A (accumulator) ; X in top of the stack - - + + #line 1 "in_screen.asm" - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -155,75 +155,75 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 2 "in_screen.asm" - - + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 9 "plot.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -236,48 +236,48 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 10 "plot.asm" - + PLOT: PROC - + LOCAL PLOT_SUB LOCAL PIXEL_ADDR LOCAL COORDS LOCAL __PLOT_ERR LOCAL P_FLAG LOCAL __PLOT_OVER1 - + P_FLAG EQU 23697 - + pop hl ex (sp), hl ; Callee - + ld b, a - ld c, h - + ld c, h + ld a, 191 cp b jr c, __PLOT_ERR ; jr is faster here (#1) - + __PLOT: ; __FASTCALL__ entry (b, c) = pixel coords (y, x) ld (COORDS), bc ; Saves current point ld a, 191 ; Max y coord @@ -285,7 +285,7 @@ __PLOT: ; __FASTCALL__ entry (b, c) = pixel coords (y, x) res 6, h ; Starts from 0 ld bc, (SCREEN_ADDR) add hl, bc ; Now current offset - + ld b, a inc b ld a, 0FEh @@ -293,7 +293,7 @@ __PLOT: ; __FASTCALL__ entry (b, c) = pixel coords (y, x) __PLOT_LOOP: rrca djnz __PLOT_LOOP - + ld b, a ld a, (P_FLAG) ld c, a @@ -301,18 +301,18 @@ __PLOT_LOOP: bit 0, c ; is it OVER 1 jr nz, __PLOT_OVER1 and b - + __PLOT_OVER1: bit 2, c ; is it inverse 1 jr nz, __PLOT_END - + xor b cpl - + LOCAL __PLOT_END __PLOT_END: ld (hl), a - + ;; gets ATTR position with offset given in SCREEN_ADDR ld a, h rrca @@ -323,36 +323,36 @@ __PLOT_END: ld h, a ld de, (SCREEN_ADDR) add hl, de ;; Final screen addr - + LOCAL PO_ATTR_2 PO_ATTR_2 EQU 0BE4h ; Another entry to PO_ATTR jp PO_ATTR_2 ; This will update attr accordingly. Beware, uses IY - + __PLOT_ERR: jp __OUT_OF_SCREEN_ERR ; Spent 3 bytes, but saves 3 T-States at (#1) - + PLOT_SUB EQU 22ECh - PIXEL_ADDR EQU 22ACh + PIXEL_ADDR EQU 22ACh COORDS EQU 5C7Dh ENDP #line 6 "circle.asm" - - + + ; Draws a circle at X, Y of radius R ; X, Y on the Stack, R in accumulator (Byte) - + PROC LOCAL __CIRCLE_ERROR LOCAL __CIRCLE_LOOP LOCAL __CIRCLE_NEXT - + __CIRCLE_ERROR: jp __OUT_OF_SCREEN_ERR ;; __CIRCLE_ERROR EQU __OUT_OF_SCREEN_ERR ;; __CIRCLE_ERROR: ;; ; Jumps here if out of screen ;; scf ; Always sets carry Flag - ;; + ;; ;; ld a, ERROR_OutOfScreen ;; ld (ERR_NR), a ;; ret @@ -362,95 +362,95 @@ CIRCLE: pop de ; D = Y ex (sp), hl ; __CALLEE__ convention ld e, h ; E = X - - - ld h, a ; H = R + + + ld h, a ; H = R add a, d sub 192 jr nc, __CIRCLE_ERROR - + ld a, d sub h jr c, __CIRCLE_ERROR - + ld a, e sub h jr c, __CIRCLE_ERROR - + ld a, h add a, e jr c, __CIRCLE_ERROR - - + + ; __FASTCALL__ Entry: D, E = Y, X point of the center ; A = Radious __CIRCLE: - push de + push de ld a, h exx pop de ; D'E' = x0, y0 ld h, a ; H' = r - + ld c, e ld a, h add a, d ld b, a call __CIRCLE_PLOT ; PLOT (x0, y0 + r) - + ld b, d ld a, h add a, e ld c, a call __CIRCLE_PLOT ; PLOT (x0 + r, y0) - + ld c, e ld a, d sub h ld b, a call __CIRCLE_PLOT ; PLOT (x0, y0 - r) - + ld b, d ld a, e sub h ld c, a call __CIRCLE_PLOT ; PLOT (x0 - r, y0) - + exx ld b, 0 ; B = x = 0 ld c, h ; C = y = Radius ld hl, 1 or a sbc hl, bc ; HL = f = 1 - radius - + ex de, hl ld hl, 0 or a sbc hl, bc ; HL = -radius add hl, hl ; HL = -2 * radius ex de, hl ; DE = -2 * radius = ddF_y, HL = f - + xor a ; A = ddF_x = 0 ex af, af' ; Saves it - + __CIRCLE_LOOP: ld a, b cp c ret nc ; Returns when x >= y - + bit 7, h ; HL >= 0? : if (f >= 0)... jp nz, __CIRCLE_NEXT - + dec c ; y-- inc de inc de ; ddF_y += 2 - + add hl, de ; f += ddF_y - + __CIRCLE_NEXT: inc b ; x++ ex af, af' add a, 2 ; 1 Cycle faster than inc a, inc a - + inc hl ; f++ push af add a, l @@ -460,11 +460,11 @@ __CIRCLE_NEXT: ld h, a pop af ex af, af' - - push bc + + push bc exx pop hl ; H'L' = Y, X - + ld a, d add a, h ld b, a ; B = y0 + y @@ -472,7 +472,7 @@ __CIRCLE_NEXT: add a, l ld c, a ; C = x0 + x call __CIRCLE_PLOT ; plot(x0 + x, y0 + y) - + ld a, d add a, h ld b, a ; B = y0 + y @@ -480,7 +480,7 @@ __CIRCLE_NEXT: sub l ld c, a ; C = x0 - x call __CIRCLE_PLOT ; plot(x0 - x, y0 + y) - + ld a, d sub h ld b, a ; B = y0 - y @@ -488,7 +488,7 @@ __CIRCLE_NEXT: add a, l ld c, a ; C = x0 + x call __CIRCLE_PLOT ; plot(x0 + x, y0 - y) - + ld a, d sub h ld b, a ; B = y0 - y @@ -496,102 +496,102 @@ __CIRCLE_NEXT: sub l ld c, a ; C = x0 - x call __CIRCLE_PLOT ; plot(x0 - x, y0 - y) - + ld a, d add a, l ld b, a ; B = y0 + x - ld a, e + ld a, e add a, h ld c, a ; C = x0 + y call __CIRCLE_PLOT ; plot(x0 + y, y0 + x) - + ld a, d add a, l ld b, a ; B = y0 + x - ld a, e + ld a, e sub h ld c, a ; C = x0 - y call __CIRCLE_PLOT ; plot(x0 - y, y0 + x) - + ld a, d sub l ld b, a ; B = y0 - x - ld a, e + ld a, e add a, h ld c, a ; C = x0 + y call __CIRCLE_PLOT ; plot(x0 + y, y0 - x) - + ld a, d sub l ld b, a ; B = y0 - x - ld a, e + ld a, e sub h ld c, a ; C = x0 + y call __CIRCLE_PLOT ; plot(x0 - y, y0 - x) - + exx jp __CIRCLE_LOOP - - - + + + __CIRCLE_PLOT: ; Plots a point of the circle, preserving HL and DE push hl push de - call __PLOT + call __PLOT pop de pop hl ret - + ENDP #line 76 "circle.bas" #line 1 "ftou32reg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "ftou32reg.asm" - + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) PROC - + LOCAL __IS_FLOAT - + or a - jr nz, __IS_FLOAT + jr nz, __IS_FLOAT ; Here if it is a ZX ROM Integer - + ld h, c ld l, d ld a, e ; Takes sign: FF = -, 0 = + @@ -599,64 +599,64 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS inc a jp z, __NEG32 ; Negates if negative ret - + __IS_FLOAT: ; Jumps here if it is a true floating point number - ld h, e + ld h, e push hl ; Stores it for later (Contains Sign in H) - + push de push bc - + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + ;ld a, c ; Get exponent sub 128 ; Exponent -= 128 jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 - + __FTOU32REG_LOOP: exx ; Shift C'B' E'D' << 1, output bit stays in Carry sla d rl e rl b rl c - + exx ; Shift DEHL << 1, inserting the carry on the right rl l rl h rl e rl d - + djnz __FTOU32REG_LOOP - + __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative jp m, __NEG32 ; Negates DEHL - + ret - + ENDP - - + + __FTOU8: ; Converts float in C ED LH to Unsigned byte in A call __FTOU32REG ld a, l ret - + #line 77 "circle.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00, 00 diff --git a/tests/functional/code00.asm b/tests/functional/code00.asm index 13a587c40..59cd0b007 100644 --- a/tests/functional/code00.asm +++ b/tests/functional/code00.asm @@ -43,12 +43,12 @@ __CALL_BACK__: __LABEL0: DEFW 0000h #line 1 "load.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -56,25 +56,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -83,51 +83,51 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -135,12 +135,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -148,7 +148,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -156,10 +156,10 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -167,25 +167,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -194,39 +194,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -234,57 +234,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -296,27 +296,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -328,7 +328,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -336,15 +336,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -369,14 +369,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -384,25 +384,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "load.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -410,25 +410,25 @@ __MEM_SUBTRACT: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -437,38 +437,38 @@ __MEM_SUBTRACT: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -477,57 +477,57 @@ __MEM_SUBTRACT: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -536,47 +536,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -586,22 +586,22 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 3 "load.asm" #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -609,46 +609,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -661,67 +661,67 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - - - + + + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -730,17 +730,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -748,26 +748,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -781,45 +781,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -830,28 +830,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -859,28 +859,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -889,50 +889,50 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - + #line 63 "/src/zxb/trunk/library-asm/copy_attr.asm" ret #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -941,32 +941,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -976,7 +976,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -984,20 +984,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -1007,7 +1007,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -1018,19 +1018,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -1040,7 +1040,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -1051,19 +1051,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -1073,7 +1073,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -1086,22 +1086,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -1110,79 +1110,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -1191,75 +1191,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -1269,7 +1269,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -1281,16 +1281,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1304,49 +1304,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1357,17 +1357,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1380,27 +1380,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1408,10 +1408,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1428,80 +1428,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1518,8 +1518,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1543,17 +1543,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1564,7 +1564,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1574,21 +1574,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1607,9 +1607,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1634,12 +1634,12 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 4 "load.asm" - + LOAD_CODE: ; This function will implement the LOAD CODE Routine ; Parameters in the stack are HL => String with LOAD name @@ -1647,9 +1647,9 @@ LOAD_CODE: ; DE = START address of CODE to save ; BC = Length of data in bytes ; A = 1 => LOAD 0 => Verify - + PROC - + LOCAL LOAD_CONT, LOAD_CONT2, LOAD_CONT3 LOCAL LD_BYTES LOCAL LOAD_HEADER @@ -1660,50 +1660,50 @@ LOAD_CODE: LOCAL LD_CH_PR LOCAL LOAD_END LOCAL VR_CONTROL, VR_CONT_1, VR_CONT_2 - + HEAD1 EQU MEM0 + 8 ; Uses CALC Mem for temporary storage ; Must skip first 8 bytes used by ; PRINT routine TMP_HEADER EQU HEAD1 + 17 ; Temporary HEADER2 pointer storage - + LD_BYTES EQU 0556h ; ROM Routine LD-BYTES TMP_FLAG EQU 23655 ; Uses BREG as a Temporary FLAG - + pop hl ; Return address pop af ; A = 1 => LOAD; A = 0 => VERIFY pop bc ; data length in bytes pop de ; address start ex (sp), hl ; CALLE => now hl = String - + __LOAD_CODE: ; INLINE version push ix ; saves IX ld (TMP_FLAG), a ; Stores verify/load flag - + ; Prepares temporary 1st header descriptor ld ix, HEAD1 ld (ix + 0), 3 ; ZXBASIC ALWAYS uses CODE ld (ix + 1), 0FFh ; Wildcard for empty string - + ld (ix + 11), c ld (ix + 12), b ; Store length in bytes ld (ix + 13), e ld (ix + 14), d ; Store address in bytes - + ld a, h or l ld b, h ld c, l jr z, LOAD_HEADER ; NULL STRING => LOAD "" - + ld c, (hl) inc hl ld b, (hl) inc hl - + ld a, b or c jr z, LOAD_CONT2 ; NULL STRING => LOAD "" - + ; Fill with blanks push hl push bc @@ -1714,7 +1714,7 @@ __LOAD_CODE: ; INLINE version ldir pop bc pop hl - + LOAD_HEADER: ex de, hl ; Saves HL in DE ld hl, 10 @@ -1723,46 +1723,46 @@ LOAD_HEADER: ex de, hl ; Retrieve HL jr nc, LOAD_CONT ; Ok BC <= 10 ld bc, 10 ; BC at most 10 chars - + LOAD_CONT: ld de, HEAD1 + 1 ldir ; Copy String block NAME in header - + LOAD_CONT2: ld bc, 17; 2nd Header call __MEM_ALLOC - + ld a, h or l jr nz, LOAD_CONT3; there's memory - + ld a, ERROR_OutOfMemory jp __ERROR - + LOAD_CONT3: ld (TMP_HEADER), hl push hl pop ix - + ;; LD-LOOK-H --- RIPPED FROM ROM at 0x767 LD_LOOK_H: push ix ; save IX ld de, 17 ; seventeen bytes xor a ; reset zero flag scf ; set carry flag - + call LD_BYTES ; routine LD-BYTES loads a header from tape ; to second descriptor. pop ix ; restore IX jr nc, LD_LOOK_H ; loop back to LD-LOOK-H until header found. - + ld c, 80h ; C has bit 7 set to indicate header type mismatch as ; a default startpoint. - + ld a, (ix + 0) ; compare loaded type cp 3 ; with expected bytes header jr nz, LD_TYPE ; forward to LD-TYPE with mis-match. - + ld c, -10 ; set C to minus ten - will count characters ; up to zero. LD_TYPE: @@ -1774,22 +1774,22 @@ LD_TYPE: ld de, (TMP_HEADER) ; point DE to 2nd descriptor. ld b, 10 ; the count will be ten characters for the ; filename. - - ld a, (hl) ; fetch first character and test for + + ld a, (hl) ; fetch first character and test for inc a ; value 255. jr nz, LD_NAME ; forward to LD-NAME if not the wildcard. - + ; but if it is the wildcard, then add ten to C which is minus ten for a type ; match or -128 for a type mismatch. Although characters have to be counted ; bit 7 of C will not alter from state set here. - + ld a, c ; transfer $F6 or $80 to A - add a, b ; add 10 + add a, b ; add 10 ld c, a ; place result, zero or -118, in C. - + ; At this point we have either a type mismatch, a wildcard match or ten ; characters to be counted. The characters must be shown on the screen. - + ;; LD-NAME LD_NAME: inc de ; address next input character @@ -1797,32 +1797,32 @@ LD_NAME: cp (hl) ; compare to expected inc hl ; address next expected character jr nz, LD_CH_PR ; forward to LD-CH-PR with mismatch - + inc c ; increment matched character count - + ;; LD-CH-PR LD_CH_PR: call __PRINTCHAR ; PRINT-A prints character djnz LD_NAME ; loop back to LD-NAME for ten characters. - + bit 7, c ; test if all matched jr nz, LD_LOOK_H ; back to LD-LOOK-H if not - + ; else print a terminal carriage return. - + ld a, 0Dh ; prepare carriage return. call __PRINTCHAR ; PRINT-A outputs it. - + ld a, (HEAD1) cp 03 ; Only "bytes:" header is used un ZX BASIC jr nz, LD_LOOK_H - + ; Ok, ready to check for bytes start and end - + VR_CONTROL: ld e, (ix + 11) ; fetch length of new data ld d, (ix + 12) ; to DE. - + ld hl, HEAD1 + 11 ld a, (hl) ; fetch length of old data (orig. header) inc hl @@ -1833,7 +1833,7 @@ VR_CONTROL: ; e.g. LOAD "x" CODE sbc hl, de jr nz, LOAD_ERROR ; Lenghts don't match - + VR_CONT_1: ld hl, HEAD1 + 13 ; fetch start of old data (orig. header) ld a, (hl) @@ -1842,56 +1842,56 @@ VR_CONT_1: ld l, a or h ; check start for zero (unespecified) jr nz, VR_CONT_2 ; Jump if there was a start - + ld l, (ix + 13) ; otherwise use destination in header ld h, (ix + 14) ; and load code at addr. saved from - + VR_CONT_2: push hl pop ix ; Transfer load addr to IX - + ld a, (TMP_FLAG) ; load verify/load flag sra a ; shift bit 0 to Carry (1 => Load, 0 = Verify), A = 0 - dec a ; a = 0xFF (Data) + dec a ; a = 0xFF (Data) call LD_BYTES jr c, LOAD_END ; if carry, load/verification was ok - + LOAD_ERROR: ; Sets ERR_NR with Tape Loading, and returns ld a, ERROR_TapeLoadingErr ld (ERR_NR), a - + LOAD_END: pop ix ; Recovers stack frame pointer ld hl, (TMP_HEADER) ; Recovers tmp_header pointer jp MEM_FREE ; Returns via FREE_MEM, freeing tmp header - + ENDP - - + + PRINT_TAPE_MESSAGES: - + PROC - + LOCAL LOOK_NEXT_TAPE_MSG LOCAL PRINT_TAPE_MSG - + ; Print tape messages according to A value - ; Each message starts with a carriage return and + ; Each message starts with a carriage return and ; ends with last char having its bit 7 set - + ; A = 0 => '\nProgram: ' ; A = 1 => '\nNumber array: ' ; A = 2 => '\nCharacter array: ' ; A = 3 => '\nBytes: ' - + push bc - + ld hl, 09C0h ; address base of last 4 tape messages ld b, a inc b ; avoid 256-loop if b == 0 - ld a, 0Dh ; Msg start mark - + ld a, 0Dh ; Msg start mark + ; skip memory bytes looking for next tape msg entry ; each msg ends when 0Dh is fond LOOK_NEXT_TAPE_MSG: @@ -1900,32 +1900,32 @@ LOOK_NEXT_TAPE_MSG: jr nz, LOOK_NEXT_TAPE_MSG ; Ok next message found djnz LOOK_NEXT_TAPE_MSG ; Repeat if more msg to skip - + PRINT_TAPE_MSG: ; Ok. This will print bytes after (HL) ; until one of them has bit 7 set ld a, (hl) and 7Fh ; Clear bit 7 of A call __PRINTCHAR - + ld a, (hl) inc hl add a, a ; Carry if A >= 128 jr nc, PRINT_TAPE_MSG - + pop bc ret - + ENDP #line 30 "code00.bas" #line 1 "loadstr.asm" - - - + + + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -1934,37 +1934,37 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) pop hl ; Recovers destiny in hl as result ret #line 31 "code00.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/code01.asm b/tests/functional/code01.asm index 969e3331f..d5bbec89e 100644 --- a/tests/functional/code01.asm +++ b/tests/functional/code01.asm @@ -43,12 +43,12 @@ __CALL_BACK__: __LABEL0: DEFW 0000h #line 1 "load.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -56,25 +56,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -83,51 +83,51 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -135,12 +135,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -148,7 +148,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -156,10 +156,10 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -167,25 +167,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -194,39 +194,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -234,57 +234,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -296,27 +296,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -328,7 +328,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -336,15 +336,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -369,14 +369,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -384,25 +384,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "load.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -410,25 +410,25 @@ __MEM_SUBTRACT: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -437,38 +437,38 @@ __MEM_SUBTRACT: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -477,57 +477,57 @@ __MEM_SUBTRACT: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -536,47 +536,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -586,22 +586,22 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 3 "load.asm" #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -609,46 +609,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -661,67 +661,67 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - - - + + + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -730,17 +730,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -748,26 +748,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -781,45 +781,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -830,28 +830,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -859,28 +859,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -889,50 +889,50 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - + #line 63 "/src/zxb/trunk/library-asm/copy_attr.asm" ret #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -941,32 +941,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -976,7 +976,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -984,20 +984,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -1007,7 +1007,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -1018,19 +1018,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -1040,7 +1040,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -1051,19 +1051,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -1073,7 +1073,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -1086,22 +1086,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -1110,79 +1110,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -1191,75 +1191,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -1269,7 +1269,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -1281,16 +1281,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1304,49 +1304,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1357,17 +1357,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1380,27 +1380,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1408,10 +1408,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1428,80 +1428,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1518,8 +1518,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1543,17 +1543,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1564,7 +1564,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1574,21 +1574,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1607,9 +1607,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1634,12 +1634,12 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 4 "load.asm" - + LOAD_CODE: ; This function will implement the LOAD CODE Routine ; Parameters in the stack are HL => String with LOAD name @@ -1647,9 +1647,9 @@ LOAD_CODE: ; DE = START address of CODE to save ; BC = Length of data in bytes ; A = 1 => LOAD 0 => Verify - + PROC - + LOCAL LOAD_CONT, LOAD_CONT2, LOAD_CONT3 LOCAL LD_BYTES LOCAL LOAD_HEADER @@ -1660,50 +1660,50 @@ LOAD_CODE: LOCAL LD_CH_PR LOCAL LOAD_END LOCAL VR_CONTROL, VR_CONT_1, VR_CONT_2 - + HEAD1 EQU MEM0 + 8 ; Uses CALC Mem for temporary storage ; Must skip first 8 bytes used by ; PRINT routine TMP_HEADER EQU HEAD1 + 17 ; Temporary HEADER2 pointer storage - + LD_BYTES EQU 0556h ; ROM Routine LD-BYTES TMP_FLAG EQU 23655 ; Uses BREG as a Temporary FLAG - + pop hl ; Return address pop af ; A = 1 => LOAD; A = 0 => VERIFY pop bc ; data length in bytes pop de ; address start ex (sp), hl ; CALLE => now hl = String - + __LOAD_CODE: ; INLINE version push ix ; saves IX ld (TMP_FLAG), a ; Stores verify/load flag - + ; Prepares temporary 1st header descriptor ld ix, HEAD1 ld (ix + 0), 3 ; ZXBASIC ALWAYS uses CODE ld (ix + 1), 0FFh ; Wildcard for empty string - + ld (ix + 11), c ld (ix + 12), b ; Store length in bytes ld (ix + 13), e ld (ix + 14), d ; Store address in bytes - + ld a, h or l ld b, h ld c, l jr z, LOAD_HEADER ; NULL STRING => LOAD "" - + ld c, (hl) inc hl ld b, (hl) inc hl - + ld a, b or c jr z, LOAD_CONT2 ; NULL STRING => LOAD "" - + ; Fill with blanks push hl push bc @@ -1714,7 +1714,7 @@ __LOAD_CODE: ; INLINE version ldir pop bc pop hl - + LOAD_HEADER: ex de, hl ; Saves HL in DE ld hl, 10 @@ -1723,46 +1723,46 @@ LOAD_HEADER: ex de, hl ; Retrieve HL jr nc, LOAD_CONT ; Ok BC <= 10 ld bc, 10 ; BC at most 10 chars - + LOAD_CONT: ld de, HEAD1 + 1 ldir ; Copy String block NAME in header - + LOAD_CONT2: ld bc, 17; 2nd Header call __MEM_ALLOC - + ld a, h or l jr nz, LOAD_CONT3; there's memory - + ld a, ERROR_OutOfMemory jp __ERROR - + LOAD_CONT3: ld (TMP_HEADER), hl push hl pop ix - + ;; LD-LOOK-H --- RIPPED FROM ROM at 0x767 LD_LOOK_H: push ix ; save IX ld de, 17 ; seventeen bytes xor a ; reset zero flag scf ; set carry flag - + call LD_BYTES ; routine LD-BYTES loads a header from tape ; to second descriptor. pop ix ; restore IX jr nc, LD_LOOK_H ; loop back to LD-LOOK-H until header found. - + ld c, 80h ; C has bit 7 set to indicate header type mismatch as ; a default startpoint. - + ld a, (ix + 0) ; compare loaded type cp 3 ; with expected bytes header jr nz, LD_TYPE ; forward to LD-TYPE with mis-match. - + ld c, -10 ; set C to minus ten - will count characters ; up to zero. LD_TYPE: @@ -1774,22 +1774,22 @@ LD_TYPE: ld de, (TMP_HEADER) ; point DE to 2nd descriptor. ld b, 10 ; the count will be ten characters for the ; filename. - - ld a, (hl) ; fetch first character and test for + + ld a, (hl) ; fetch first character and test for inc a ; value 255. jr nz, LD_NAME ; forward to LD-NAME if not the wildcard. - + ; but if it is the wildcard, then add ten to C which is minus ten for a type ; match or -128 for a type mismatch. Although characters have to be counted ; bit 7 of C will not alter from state set here. - + ld a, c ; transfer $F6 or $80 to A - add a, b ; add 10 + add a, b ; add 10 ld c, a ; place result, zero or -118, in C. - + ; At this point we have either a type mismatch, a wildcard match or ten ; characters to be counted. The characters must be shown on the screen. - + ;; LD-NAME LD_NAME: inc de ; address next input character @@ -1797,32 +1797,32 @@ LD_NAME: cp (hl) ; compare to expected inc hl ; address next expected character jr nz, LD_CH_PR ; forward to LD-CH-PR with mismatch - + inc c ; increment matched character count - + ;; LD-CH-PR LD_CH_PR: call __PRINTCHAR ; PRINT-A prints character djnz LD_NAME ; loop back to LD-NAME for ten characters. - + bit 7, c ; test if all matched jr nz, LD_LOOK_H ; back to LD-LOOK-H if not - + ; else print a terminal carriage return. - + ld a, 0Dh ; prepare carriage return. call __PRINTCHAR ; PRINT-A outputs it. - + ld a, (HEAD1) cp 03 ; Only "bytes:" header is used un ZX BASIC jr nz, LD_LOOK_H - + ; Ok, ready to check for bytes start and end - + VR_CONTROL: ld e, (ix + 11) ; fetch length of new data ld d, (ix + 12) ; to DE. - + ld hl, HEAD1 + 11 ld a, (hl) ; fetch length of old data (orig. header) inc hl @@ -1833,7 +1833,7 @@ VR_CONTROL: ; e.g. LOAD "x" CODE sbc hl, de jr nz, LOAD_ERROR ; Lenghts don't match - + VR_CONT_1: ld hl, HEAD1 + 13 ; fetch start of old data (orig. header) ld a, (hl) @@ -1842,56 +1842,56 @@ VR_CONT_1: ld l, a or h ; check start for zero (unespecified) jr nz, VR_CONT_2 ; Jump if there was a start - + ld l, (ix + 13) ; otherwise use destination in header ld h, (ix + 14) ; and load code at addr. saved from - + VR_CONT_2: push hl pop ix ; Transfer load addr to IX - + ld a, (TMP_FLAG) ; load verify/load flag sra a ; shift bit 0 to Carry (1 => Load, 0 = Verify), A = 0 - dec a ; a = 0xFF (Data) + dec a ; a = 0xFF (Data) call LD_BYTES jr c, LOAD_END ; if carry, load/verification was ok - + LOAD_ERROR: ; Sets ERR_NR with Tape Loading, and returns ld a, ERROR_TapeLoadingErr ld (ERR_NR), a - + LOAD_END: pop ix ; Recovers stack frame pointer ld hl, (TMP_HEADER) ; Recovers tmp_header pointer jp MEM_FREE ; Returns via FREE_MEM, freeing tmp header - + ENDP - - + + PRINT_TAPE_MESSAGES: - + PROC - + LOCAL LOOK_NEXT_TAPE_MSG LOCAL PRINT_TAPE_MSG - + ; Print tape messages according to A value - ; Each message starts with a carriage return and + ; Each message starts with a carriage return and ; ends with last char having its bit 7 set - + ; A = 0 => '\nProgram: ' ; A = 1 => '\nNumber array: ' ; A = 2 => '\nCharacter array: ' ; A = 3 => '\nBytes: ' - + push bc - + ld hl, 09C0h ; address base of last 4 tape messages ld b, a inc b ; avoid 256-loop if b == 0 - ld a, 0Dh ; Msg start mark - + ld a, 0Dh ; Msg start mark + ; skip memory bytes looking for next tape msg entry ; each msg ends when 0Dh is fond LOOK_NEXT_TAPE_MSG: @@ -1900,32 +1900,32 @@ LOOK_NEXT_TAPE_MSG: jr nz, LOOK_NEXT_TAPE_MSG ; Ok next message found djnz LOOK_NEXT_TAPE_MSG ; Repeat if more msg to skip - + PRINT_TAPE_MSG: ; Ok. This will print bytes after (HL) ; until one of them has bit 7 set ld a, (hl) and 7Fh ; Clear bit 7 of A call __PRINTCHAR - + ld a, (hl) inc hl add a, a ; Carry if A >= 128 jr nc, PRINT_TAPE_MSG - + pop bc ret - + ENDP #line 30 "code01.bas" #line 1 "loadstr.asm" - - - + + + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -1934,37 +1934,37 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) pop hl ; Recovers destiny in hl as result ret #line 31 "code01.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/code02.asm b/tests/functional/code02.asm index fcba8da57..f748f23ed 100644 --- a/tests/functional/code02.asm +++ b/tests/functional/code02.asm @@ -43,12 +43,12 @@ __CALL_BACK__: __LABEL0: DEFW 0000h #line 1 "load.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -56,25 +56,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -83,51 +83,51 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -135,12 +135,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -148,7 +148,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -156,10 +156,10 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -167,25 +167,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -194,39 +194,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -234,57 +234,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -296,27 +296,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -328,7 +328,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -336,15 +336,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -369,14 +369,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -384,25 +384,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "load.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -410,25 +410,25 @@ __MEM_SUBTRACT: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -437,38 +437,38 @@ __MEM_SUBTRACT: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -477,57 +477,57 @@ __MEM_SUBTRACT: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -536,47 +536,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -586,22 +586,22 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 3 "load.asm" #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -609,46 +609,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -661,67 +661,67 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - - - + + + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -730,17 +730,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -748,26 +748,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -781,45 +781,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -830,28 +830,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -859,28 +859,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -889,50 +889,50 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - + #line 63 "/src/zxb/trunk/library-asm/copy_attr.asm" ret #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -941,32 +941,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -976,7 +976,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -984,20 +984,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -1007,7 +1007,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -1018,19 +1018,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -1040,7 +1040,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -1051,19 +1051,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -1073,7 +1073,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -1086,22 +1086,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -1110,79 +1110,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -1191,75 +1191,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -1269,7 +1269,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -1281,16 +1281,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1304,49 +1304,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1357,17 +1357,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1380,27 +1380,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1408,10 +1408,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1428,80 +1428,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1518,8 +1518,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1543,17 +1543,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1564,7 +1564,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1574,21 +1574,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1607,9 +1607,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1634,12 +1634,12 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 4 "load.asm" - + LOAD_CODE: ; This function will implement the LOAD CODE Routine ; Parameters in the stack are HL => String with LOAD name @@ -1647,9 +1647,9 @@ LOAD_CODE: ; DE = START address of CODE to save ; BC = Length of data in bytes ; A = 1 => LOAD 0 => Verify - + PROC - + LOCAL LOAD_CONT, LOAD_CONT2, LOAD_CONT3 LOCAL LD_BYTES LOCAL LOAD_HEADER @@ -1660,50 +1660,50 @@ LOAD_CODE: LOCAL LD_CH_PR LOCAL LOAD_END LOCAL VR_CONTROL, VR_CONT_1, VR_CONT_2 - + HEAD1 EQU MEM0 + 8 ; Uses CALC Mem for temporary storage ; Must skip first 8 bytes used by ; PRINT routine TMP_HEADER EQU HEAD1 + 17 ; Temporary HEADER2 pointer storage - + LD_BYTES EQU 0556h ; ROM Routine LD-BYTES TMP_FLAG EQU 23655 ; Uses BREG as a Temporary FLAG - + pop hl ; Return address pop af ; A = 1 => LOAD; A = 0 => VERIFY pop bc ; data length in bytes pop de ; address start ex (sp), hl ; CALLE => now hl = String - + __LOAD_CODE: ; INLINE version push ix ; saves IX ld (TMP_FLAG), a ; Stores verify/load flag - + ; Prepares temporary 1st header descriptor ld ix, HEAD1 ld (ix + 0), 3 ; ZXBASIC ALWAYS uses CODE ld (ix + 1), 0FFh ; Wildcard for empty string - + ld (ix + 11), c ld (ix + 12), b ; Store length in bytes ld (ix + 13), e ld (ix + 14), d ; Store address in bytes - + ld a, h or l ld b, h ld c, l jr z, LOAD_HEADER ; NULL STRING => LOAD "" - + ld c, (hl) inc hl ld b, (hl) inc hl - + ld a, b or c jr z, LOAD_CONT2 ; NULL STRING => LOAD "" - + ; Fill with blanks push hl push bc @@ -1714,7 +1714,7 @@ __LOAD_CODE: ; INLINE version ldir pop bc pop hl - + LOAD_HEADER: ex de, hl ; Saves HL in DE ld hl, 10 @@ -1723,46 +1723,46 @@ LOAD_HEADER: ex de, hl ; Retrieve HL jr nc, LOAD_CONT ; Ok BC <= 10 ld bc, 10 ; BC at most 10 chars - + LOAD_CONT: ld de, HEAD1 + 1 ldir ; Copy String block NAME in header - + LOAD_CONT2: ld bc, 17; 2nd Header call __MEM_ALLOC - + ld a, h or l jr nz, LOAD_CONT3; there's memory - + ld a, ERROR_OutOfMemory jp __ERROR - + LOAD_CONT3: ld (TMP_HEADER), hl push hl pop ix - + ;; LD-LOOK-H --- RIPPED FROM ROM at 0x767 LD_LOOK_H: push ix ; save IX ld de, 17 ; seventeen bytes xor a ; reset zero flag scf ; set carry flag - + call LD_BYTES ; routine LD-BYTES loads a header from tape ; to second descriptor. pop ix ; restore IX jr nc, LD_LOOK_H ; loop back to LD-LOOK-H until header found. - + ld c, 80h ; C has bit 7 set to indicate header type mismatch as ; a default startpoint. - + ld a, (ix + 0) ; compare loaded type cp 3 ; with expected bytes header jr nz, LD_TYPE ; forward to LD-TYPE with mis-match. - + ld c, -10 ; set C to minus ten - will count characters ; up to zero. LD_TYPE: @@ -1774,22 +1774,22 @@ LD_TYPE: ld de, (TMP_HEADER) ; point DE to 2nd descriptor. ld b, 10 ; the count will be ten characters for the ; filename. - - ld a, (hl) ; fetch first character and test for + + ld a, (hl) ; fetch first character and test for inc a ; value 255. jr nz, LD_NAME ; forward to LD-NAME if not the wildcard. - + ; but if it is the wildcard, then add ten to C which is minus ten for a type ; match or -128 for a type mismatch. Although characters have to be counted ; bit 7 of C will not alter from state set here. - + ld a, c ; transfer $F6 or $80 to A - add a, b ; add 10 + add a, b ; add 10 ld c, a ; place result, zero or -118, in C. - + ; At this point we have either a type mismatch, a wildcard match or ten ; characters to be counted. The characters must be shown on the screen. - + ;; LD-NAME LD_NAME: inc de ; address next input character @@ -1797,32 +1797,32 @@ LD_NAME: cp (hl) ; compare to expected inc hl ; address next expected character jr nz, LD_CH_PR ; forward to LD-CH-PR with mismatch - + inc c ; increment matched character count - + ;; LD-CH-PR LD_CH_PR: call __PRINTCHAR ; PRINT-A prints character djnz LD_NAME ; loop back to LD-NAME for ten characters. - + bit 7, c ; test if all matched jr nz, LD_LOOK_H ; back to LD-LOOK-H if not - + ; else print a terminal carriage return. - + ld a, 0Dh ; prepare carriage return. call __PRINTCHAR ; PRINT-A outputs it. - + ld a, (HEAD1) cp 03 ; Only "bytes:" header is used un ZX BASIC jr nz, LD_LOOK_H - + ; Ok, ready to check for bytes start and end - + VR_CONTROL: ld e, (ix + 11) ; fetch length of new data ld d, (ix + 12) ; to DE. - + ld hl, HEAD1 + 11 ld a, (hl) ; fetch length of old data (orig. header) inc hl @@ -1833,7 +1833,7 @@ VR_CONTROL: ; e.g. LOAD "x" CODE sbc hl, de jr nz, LOAD_ERROR ; Lenghts don't match - + VR_CONT_1: ld hl, HEAD1 + 13 ; fetch start of old data (orig. header) ld a, (hl) @@ -1842,56 +1842,56 @@ VR_CONT_1: ld l, a or h ; check start for zero (unespecified) jr nz, VR_CONT_2 ; Jump if there was a start - + ld l, (ix + 13) ; otherwise use destination in header ld h, (ix + 14) ; and load code at addr. saved from - + VR_CONT_2: push hl pop ix ; Transfer load addr to IX - + ld a, (TMP_FLAG) ; load verify/load flag sra a ; shift bit 0 to Carry (1 => Load, 0 = Verify), A = 0 - dec a ; a = 0xFF (Data) + dec a ; a = 0xFF (Data) call LD_BYTES jr c, LOAD_END ; if carry, load/verification was ok - + LOAD_ERROR: ; Sets ERR_NR with Tape Loading, and returns ld a, ERROR_TapeLoadingErr ld (ERR_NR), a - + LOAD_END: pop ix ; Recovers stack frame pointer ld hl, (TMP_HEADER) ; Recovers tmp_header pointer jp MEM_FREE ; Returns via FREE_MEM, freeing tmp header - + ENDP - - + + PRINT_TAPE_MESSAGES: - + PROC - + LOCAL LOOK_NEXT_TAPE_MSG LOCAL PRINT_TAPE_MSG - + ; Print tape messages according to A value - ; Each message starts with a carriage return and + ; Each message starts with a carriage return and ; ends with last char having its bit 7 set - + ; A = 0 => '\nProgram: ' ; A = 1 => '\nNumber array: ' ; A = 2 => '\nCharacter array: ' ; A = 3 => '\nBytes: ' - + push bc - + ld hl, 09C0h ; address base of last 4 tape messages ld b, a inc b ; avoid 256-loop if b == 0 - ld a, 0Dh ; Msg start mark - + ld a, 0Dh ; Msg start mark + ; skip memory bytes looking for next tape msg entry ; each msg ends when 0Dh is fond LOOK_NEXT_TAPE_MSG: @@ -1900,32 +1900,32 @@ LOOK_NEXT_TAPE_MSG: jr nz, LOOK_NEXT_TAPE_MSG ; Ok next message found djnz LOOK_NEXT_TAPE_MSG ; Repeat if more msg to skip - + PRINT_TAPE_MSG: ; Ok. This will print bytes after (HL) ; until one of them has bit 7 set ld a, (hl) and 7Fh ; Clear bit 7 of A call __PRINTCHAR - + ld a, (hl) inc hl add a, a ; Carry if A >= 128 jr nc, PRINT_TAPE_MSG - + pop bc ret - + ENDP #line 30 "code02.bas" #line 1 "loadstr.asm" - - - + + + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -1934,37 +1934,37 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) pop hl ; Recovers destiny in hl as result ret #line 31 "code02.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/codecrash1.asm b/tests/functional/codecrash1.asm index 28fa2d37b..bed8b50e4 100644 --- a/tests/functional/codecrash1.asm +++ b/tests/functional/codecrash1.asm @@ -34,13 +34,13 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "asc.asm" - + ; Returns the ascii code for the given str #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -48,25 +48,25 @@ __CALL_BACK__: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -75,41 +75,41 @@ __CALL_BACK__: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -117,25 +117,25 @@ __CALL_BACK__: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -144,39 +144,39 @@ __CALL_BACK__: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -184,56 +184,56 @@ __CALL_BACK__: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -242,57 +242,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -301,47 +301,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -351,45 +351,45 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 3 "asc.asm" - + __ASC: PROC LOCAL __ASC_END - + ex af, af' ; Saves free_mem flag - + ld a, h or l ret z ; NULL? return - + ld c, (hl) inc hl ld b, (hl) - + ld a, b or c jr z, __ASC_END ; No length? return - + inc hl ld a, (hl) dec hl - + __ASC_END: dec hl ex af, af' or a call nz, __MEM_FREE ; Free memory if needed - + ex af, af' ; Recover result - + ret ENDP #line 22 "codecrash1.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/codecrash2.asm b/tests/functional/codecrash2.asm index 651f83076..62f693d81 100644 --- a/tests/functional/codecrash2.asm +++ b/tests/functional/codecrash2.asm @@ -36,13 +36,13 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "asc.asm" - + ; Returns the ascii code for the given str #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -50,25 +50,25 @@ __CALL_BACK__: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -77,41 +77,41 @@ __CALL_BACK__: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -119,25 +119,25 @@ __CALL_BACK__: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -146,39 +146,39 @@ __CALL_BACK__: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -186,56 +186,56 @@ __CALL_BACK__: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -244,57 +244,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -303,47 +303,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -353,51 +353,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 3 "asc.asm" - + __ASC: PROC LOCAL __ASC_END - + ex af, af' ; Saves free_mem flag - + ld a, h or l ret z ; NULL? return - + ld c, (hl) inc hl ld b, (hl) - + ld a, b or c jr z, __ASC_END ; No length? return - + inc hl ld a, (hl) dec hl - + __ASC_END: dec hl ex af, af' or a call nz, __MEM_FREE ; Free memory if needed - + ex af, af' ; Recover result - + ret ENDP #line 24 "codecrash2.bas" #line 1 "strcat.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -405,25 +405,25 @@ __ASC_END: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -432,51 +432,51 @@ __ASC_END: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -484,12 +484,12 @@ __ASC_END: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -497,16 +497,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -518,27 +518,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -550,7 +550,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -558,15 +558,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -591,14 +591,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -606,114 +606,114 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "strcat.asm" #line 1 "strlen.asm" - + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL - + __STRLEN: ; Direct FASTCALL entry ld a, h or l ret z - + ld a, (hl) inc hl ld h, (hl) ; LEN(str) in HL ld l, a ret - - + + #line 3 "strcat.asm" - + __ADDSTR: ; Implements c$ = a$ + b$ ; hl = &a$, de = &b$ (pointers) - - + + __STRCAT2: ; This routine creates a new string in dynamic space ; making room for it. Then copies a$ + b$ into it. ; HL = a$, DE = b$ - + PROC - + LOCAL __STR_CONT LOCAL __STRCATEND - + push hl call __STRLEN ld c, l ld b, h ; BC = LEN(a$) ex (sp), hl ; (SP) = LEN (a$), HL = a$ push hl ; Saves pointer to a$ - + inc bc inc bc ; +2 bytes to store length - + ex de, hl push hl call __STRLEN ; HL = len(b$) - + add hl, bc ; Total str length => 2 + len(a$) + len(b$) - + ld c, l ld b, h ; BC = Total str length + 2 - call __MEM_ALLOC - pop de ; HL = c$, DE = b$ - + call __MEM_ALLOC + pop de ; HL = c$, DE = b$ + ex de, hl ; HL = b$, DE = c$ - ex (sp), hl ; HL = a$, (SP) = b$ - + ex (sp), hl ; HL = a$, (SP) = b$ + exx - pop de ; D'E' = b$ + pop de ; D'E' = b$ exx - + pop bc ; LEN(a$) - + ld a, d or e ret z ; If no memory: RETURN - + __STR_CONT: push de ; Address of c$ - + ld a, h or l jr nz, __STR_CONT1 ; If len(a$) != 0 do copy - + ; a$ is NULL => uses HL = DE for transfer ld h, d ld l, e ld (hl), a ; This will copy 00 00 at (DE) location - inc de ; + inc de ; dec bc ; Ensure BC will be set to 1 in the next step - + __STR_CONT1: ; Copies a$ (HL) into c$ (DE) - inc bc + inc bc inc bc ; BC = BC + 2 ldir ; MEMCOPY: c$ = a$ pop hl ; HL = c$ - + exx push de ; Recovers b$; A ex hl,hl' would be very handy exx - - pop de ; DE = b$ - + + pop de ; DE = b$ + __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ; NOTE: Both DE, BC and AF are modified and lost ; Returns HL (pointer to a$) @@ -721,50 +721,50 @@ __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ld a, d or e ret z ; Returns if de is NULL (nothing to copy) - + push hl ; Saves HL to return it later - + ld c, (hl) inc hl ld b, (hl) inc hl add hl, bc ; HL = end of (a$) string ; bc = len(a$) push bc ; Saves LEN(a$) for later - + ex de, hl ; DE = end of string (Begin of copy addr) ld c, (hl) inc hl ld b, (hl) ; BC = len(b$) - + ld a, b or c jr z, __STRCATEND; Return if len(b$) == 0 - + push bc ; Save LEN(b$) inc hl ; Skip 2nd byte of len(b$) ldir ; Concatenate b$ - + pop bc ; Recovers length (b$) pop hl ; Recovers length (a$) add hl, bc ; HL = LEN(a$) + LEN(b$) = LEN(a$+b$) ex de, hl ; DE = LEN(a$+b$) pop hl - + ld (hl), e ; Updates new LEN and return inc hl ld (hl), d dec hl ret - + __STRCATEND: pop hl ; Removes Len(a$) pop hl ; Restores original HL, so HL = a$ ret - + ENDP - + #line 25 "codecrash2.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/codecrash3.asm b/tests/functional/codecrash3.asm index e8160e71b..aa4eacfec 100644 --- a/tests/functional/codecrash3.asm +++ b/tests/functional/codecrash3.asm @@ -34,13 +34,13 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "asc.asm" - + ; Returns the ascii code for the given str #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -48,25 +48,25 @@ __CALL_BACK__: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -75,41 +75,41 @@ __CALL_BACK__: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -117,25 +117,25 @@ __CALL_BACK__: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -144,39 +144,39 @@ __CALL_BACK__: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -184,56 +184,56 @@ __CALL_BACK__: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -242,57 +242,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -301,47 +301,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -351,56 +351,56 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 3 "asc.asm" - + __ASC: PROC LOCAL __ASC_END - + ex af, af' ; Saves free_mem flag - + ld a, h or l ret z ; NULL? return - + ld c, (hl) inc hl ld b, (hl) - + ld a, b or c jr z, __ASC_END ; No length? return - + inc hl ld a, (hl) dec hl - + __ASC_END: dec hl ex af, af' or a call nz, __MEM_FREE ; Free memory if needed - + ex af, af' ; Recover result - + ret ENDP #line 22 "codecrash3.bas" #line 1 "inkey.asm" - + ; INKEY Function ; Returns a string allocated in dynamic memory ; containing the string. ; An empty string otherwise. - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -408,25 +408,25 @@ __ASC_END: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -435,51 +435,51 @@ __ASC_END: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -487,12 +487,12 @@ __ASC_END: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -500,16 +500,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -521,27 +521,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -553,7 +553,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -561,15 +561,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -594,14 +594,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -609,50 +609,50 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 7 "inkey.asm" - + INKEY: - PROC + PROC LOCAL __EMPTY_INKEY LOCAL KEY_SCAN LOCAL KEY_TEST LOCAL KEY_CODE - - ld bc, 3 ; 1 char length string + + ld bc, 3 ; 1 char length string call __MEM_ALLOC - + ld a, h or l ret z ; Return if NULL (No memory) - + push hl ; Saves memory pointer - + call KEY_SCAN jp nz, __EMPTY_INKEY - + call KEY_TEST jp nc, __EMPTY_INKEY - + dec d ; D is expected to be FLAGS so set bit 3 $FF ; 'L' Mode so no keywords. ld e, a ; main key to A ; C is MODE 0 'KLC' from above still. call KEY_CODE ; routine K-DECODE pop hl - + ld (hl), 1 inc hl ld (hl), 0 @@ -661,7 +661,7 @@ INKEY: dec hl dec hl ; HL Points to string result ret - + __EMPTY_INKEY: pop hl xor a @@ -670,15 +670,15 @@ __EMPTY_INKEY: ld (hl), a dec hl ret - + KEY_SCAN EQU 028Eh KEY_TEST EQU 031Eh KEY_CODE EQU 0333h - + ENDP - + #line 23 "codecrash3.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/codecrash4.asm b/tests/functional/codecrash4.asm index 08c20f9f2..485df0f9c 100644 --- a/tests/functional/codecrash4.asm +++ b/tests/functional/codecrash4.asm @@ -44,13 +44,13 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "asc.asm" - + ; Returns the ascii code for the given str #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -58,25 +58,25 @@ __CALL_BACK__: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -85,41 +85,41 @@ __CALL_BACK__: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -127,25 +127,25 @@ __CALL_BACK__: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -154,39 +154,39 @@ __CALL_BACK__: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -194,56 +194,56 @@ __CALL_BACK__: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -252,57 +252,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -311,47 +311,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -361,56 +361,56 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 3 "asc.asm" - + __ASC: PROC LOCAL __ASC_END - + ex af, af' ; Saves free_mem flag - + ld a, h or l ret z ; NULL? return - + ld c, (hl) inc hl ld b, (hl) - + ld a, b or c jr z, __ASC_END ; No length? return - + inc hl ld a, (hl) dec hl - + __ASC_END: dec hl ex af, af' or a call nz, __MEM_FREE ; Free memory if needed - + ex af, af' ; Recover result - + ret ENDP #line 32 "codecrash4.bas" #line 1 "inkey.asm" - + ; INKEY Function ; Returns a string allocated in dynamic memory ; containing the string. ; An empty string otherwise. - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -418,25 +418,25 @@ __ASC_END: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -445,51 +445,51 @@ __ASC_END: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -497,12 +497,12 @@ __ASC_END: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -510,16 +510,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -531,27 +531,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -563,7 +563,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -571,15 +571,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -604,14 +604,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -619,50 +619,50 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 7 "inkey.asm" - + INKEY: - PROC + PROC LOCAL __EMPTY_INKEY LOCAL KEY_SCAN LOCAL KEY_TEST LOCAL KEY_CODE - - ld bc, 3 ; 1 char length string + + ld bc, 3 ; 1 char length string call __MEM_ALLOC - + ld a, h or l ret z ; Return if NULL (No memory) - + push hl ; Saves memory pointer - + call KEY_SCAN jp nz, __EMPTY_INKEY - + call KEY_TEST jp nc, __EMPTY_INKEY - + dec d ; D is expected to be FLAGS so set bit 3 $FF ; 'L' Mode so no keywords. ld e, a ; main key to A ; C is MODE 0 'KLC' from above still. call KEY_CODE ; routine K-DECODE pop hl - + ld (hl), 1 inc hl ld (hl), 0 @@ -671,7 +671,7 @@ INKEY: dec hl dec hl ; HL Points to string result ret - + __EMPTY_INKEY: pop hl xor a @@ -680,111 +680,111 @@ __EMPTY_INKEY: ld (hl), a dec hl ret - + KEY_SCAN EQU 028Eh KEY_TEST EQU 031Eh KEY_CODE EQU 0333h - + ENDP - + #line 33 "codecrash4.bas" #line 1 "strcat.asm" - - + + #line 1 "strlen.asm" - + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL - + __STRLEN: ; Direct FASTCALL entry ld a, h or l ret z - + ld a, (hl) inc hl ld h, (hl) ; LEN(str) in HL ld l, a ret - - + + #line 3 "strcat.asm" - + __ADDSTR: ; Implements c$ = a$ + b$ ; hl = &a$, de = &b$ (pointers) - - + + __STRCAT2: ; This routine creates a new string in dynamic space ; making room for it. Then copies a$ + b$ into it. ; HL = a$, DE = b$ - + PROC - + LOCAL __STR_CONT LOCAL __STRCATEND - + push hl call __STRLEN ld c, l ld b, h ; BC = LEN(a$) ex (sp), hl ; (SP) = LEN (a$), HL = a$ push hl ; Saves pointer to a$ - + inc bc inc bc ; +2 bytes to store length - + ex de, hl push hl call __STRLEN ; HL = len(b$) - + add hl, bc ; Total str length => 2 + len(a$) + len(b$) - + ld c, l ld b, h ; BC = Total str length + 2 - call __MEM_ALLOC - pop de ; HL = c$, DE = b$ - + call __MEM_ALLOC + pop de ; HL = c$, DE = b$ + ex de, hl ; HL = b$, DE = c$ - ex (sp), hl ; HL = a$, (SP) = b$ - + ex (sp), hl ; HL = a$, (SP) = b$ + exx - pop de ; D'E' = b$ + pop de ; D'E' = b$ exx - + pop bc ; LEN(a$) - + ld a, d or e ret z ; If no memory: RETURN - + __STR_CONT: push de ; Address of c$ - + ld a, h or l jr nz, __STR_CONT1 ; If len(a$) != 0 do copy - + ; a$ is NULL => uses HL = DE for transfer ld h, d ld l, e ld (hl), a ; This will copy 00 00 at (DE) location - inc de ; + inc de ; dec bc ; Ensure BC will be set to 1 in the next step - + __STR_CONT1: ; Copies a$ (HL) into c$ (DE) - inc bc + inc bc inc bc ; BC = BC + 2 ldir ; MEMCOPY: c$ = a$ pop hl ; HL = c$ - + exx push de ; Recovers b$; A ex hl,hl' would be very handy exx - - pop de ; DE = b$ - + + pop de ; DE = b$ + __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ; NOTE: Both DE, BC and AF are modified and lost ; Returns HL (pointer to a$) @@ -792,50 +792,50 @@ __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ld a, d or e ret z ; Returns if de is NULL (nothing to copy) - + push hl ; Saves HL to return it later - + ld c, (hl) inc hl ld b, (hl) inc hl add hl, bc ; HL = end of (a$) string ; bc = len(a$) push bc ; Saves LEN(a$) for later - + ex de, hl ; DE = end of string (Begin of copy addr) ld c, (hl) inc hl ld b, (hl) ; BC = len(b$) - + ld a, b or c jr z, __STRCATEND; Return if len(b$) == 0 - + push bc ; Save LEN(b$) inc hl ; Skip 2nd byte of len(b$) ldir ; Concatenate b$ - + pop bc ; Recovers length (b$) pop hl ; Recovers length (a$) add hl, bc ; HL = LEN(a$) + LEN(b$) = LEN(a$+b$) ex de, hl ; DE = LEN(a$+b$) pop hl - + ld (hl), e ; Updates new LEN and return inc hl ld (hl), d dec hl ret - + __STRCATEND: pop hl ; Removes Len(a$) pop hl ; Restores original HL, so HL = a$ ret - + ENDP - + #line 34 "codecrash4.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/coercion1.asm b/tests/functional/coercion1.asm index c4e656ee5..37983f6b3 100644 --- a/tests/functional/coercion1.asm +++ b/tests/functional/coercion1.asm @@ -68,40 +68,40 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "addf.asm" - + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -117,7 +117,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 2 "addf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) ; All of them uses A EDCB registers as 1st paramter. @@ -126,46 +126,46 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; ; Uses CALLEE convention ; ------------------------------------------------------------- - + __ADDF: ; Addition call __FPSTACK_PUSH2 - + ; ------------- ROM ADD rst 28h defb 0fh ; ADD defb 38h; ; END CALC - + jp __FPSTACK_POP - + #line 59 "coercion1.bas" #line 1 "border.asm" - + ; __FASTCALL__ Routine to change de border ; Parameter (color) specified in A register - + BORDER EQU 229Bh - + ; Nothing to do! (Directly from the ZX Spectrum ROM) - + #line 60 "coercion1.bas" #line 1 "divf.asm" - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -173,12 +173,12 @@ __ADDF: ; Addition ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -186,34 +186,34 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "divf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) - + ; All of them uses C EDHL registers as 1st paramter. ; For binary operators, the 2n operator must be pushed into the ; stack, in the order BC DE HL (B not used). ; ; Uses CALLEE convention ; ------------------------------------------------------------- - + __DIVF: ; Division PROC LOCAL __DIVBYZERO LOCAL TMP, ERR_SP - + TMP EQU 23629 ;(DEST) ERR_SP EQU 23613 - + call __FPSTACK_PUSH2 - + ld hl, (ERR_SP) ld (TMP), hl ld hl, __DIVBYZERO @@ -221,26 +221,26 @@ __DIVF: ; Division ld hl, 0 add hl, sp ld (ERR_SP), hl - + ; ------------- ROM DIV rst 28h defb 01h ; EXCHANGE defb 05h ; DIV defb 38h; ; END CALC - + pop hl ld hl, (TMP) ld (ERR_SP), hl - + jp __FPSTACK_POP - + __DIVBYZERO: ld hl, (TMP) ld (ERR_SP), hl - + ld a, ERROR_NumberTooBig ld (ERR_NR), a - + ; Returns 0 on DIV BY ZERO error xor a ld b, a @@ -248,57 +248,57 @@ __DIVBYZERO: ld d, a ld e, a ret - + ENDP - + #line 61 "coercion1.bas" #line 1 "ftou32reg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "ftou32reg.asm" - + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) PROC - + LOCAL __IS_FLOAT - + or a - jr nz, __IS_FLOAT + jr nz, __IS_FLOAT ; Here if it is a ZX ROM Integer - + ld h, c ld l, d ld a, e ; Takes sign: FF = -, 0 = + @@ -306,81 +306,81 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS inc a jp z, __NEG32 ; Negates if negative ret - + __IS_FLOAT: ; Jumps here if it is a true floating point number - ld h, e + ld h, e push hl ; Stores it for later (Contains Sign in H) - + push de push bc - + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + ;ld a, c ; Get exponent sub 128 ; Exponent -= 128 jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 - + __FTOU32REG_LOOP: exx ; Shift C'B' E'D' << 1, output bit stays in Carry sla d rl e rl b rl c - + exx ; Shift DEHL << 1, inserting the carry on the right rl l rl h rl e rl d - + djnz __FTOU32REG_LOOP - + __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative jp m, __NEG32 ; Negates DEHL - + ret - + ENDP - - + + __FTOU8: ; Converts float in C ED LH to Unsigned byte in A call __FTOU32REG ld a, l ret - + #line 62 "coercion1.bas" #line 1 "mul8.asm" - + __MUL8: ; Performs 8bit x 8bit multiplication PROC - + ;LOCAL __MUL8A LOCAL __MUL8LOOP LOCAL __MUL8B ; 1st operand (byte) in A, 2nd operand into the stack (AF) pop hl ; return address ex (sp), hl ; CALLE convention - + ;;__MUL8_FAST: ; __FASTCALL__ entry ;; ld e, a ;; ld d, 0 ;; ld l, d - ;; - ;; sla h + ;; + ;; sla h ;; jr nc, __MUL8A ;; ld l, e ;; @@ -397,30 +397,30 @@ __MUL8: ; Performs 8bit x 8bit multiplication ;; djnz __MUL8LOOP ;; ;; ld a, l ; result = A and HL (Truncate to lower 8 bits) - + __MUL8_FAST: ; __FASTCALL__ entry, a = a * h (8 bit mul) and Carry - + ld b, 8 ld l, a xor a - + __MUL8LOOP: add a, a ; a *= 2 sla l jp nc, __MUL8B add a, h - + __MUL8B: djnz __MUL8LOOP - + ret ; result = HL ENDP - + #line 63 "coercion1.bas" #line 1 "mulf.asm" - - - + + + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) ; All of them uses A EDCB registers as 1st paramter. @@ -429,26 +429,26 @@ __MUL8B: ; ; Uses CALLEE convention ; ------------------------------------------------------------- - + __MULF: ; Multiplication call __FPSTACK_PUSH2 - + ; ------------- ROM MUL rst 28h - defb 04h ; + defb 04h ; defb 38h; ; END CALC - + jp __FPSTACK_POP - + #line 64 "coercion1.bas" #line 1 "pushf.asm" - - - ; Routine to push Float pointed by HL + + + ; Routine to push Float pointed by HL ; Into the stack. Notice that the hl points to the last ; byte of the FP number. ; Uses H'L' B'C' and D'E' to preserve ABCDEHL registers - + __FP_PUSH_REV: push hl exx @@ -469,10 +469,10 @@ __FP_PUSH_REV: push bc ; Return Address exx ret - - + + #line 65 "coercion1.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00, 00 diff --git a/tests/functional/coercion3.asm b/tests/functional/coercion3.asm index b9c24c7e3..2cd583dcc 100644 --- a/tests/functional/coercion3.asm +++ b/tests/functional/coercion3.asm @@ -39,13 +39,13 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "copy_attr.asm" - + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -53,35 +53,35 @@ __CALL_BACK__: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 6 "copy_attr.asm" - + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - + #line 63 "/src/zxb/trunk/library-asm/copy_attr.asm" ret #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -90,40 +90,40 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 30 "coercion3.bas" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -134,16 +134,16 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 31 "coercion3.bas" - + ZXBASIC_USER_DATA: _c: DEFB 04h diff --git a/tests/functional/const0.asm b/tests/functional/const0.asm index ec7fef5c3..9e4b187ec 100644 --- a/tests/functional/const0.asm +++ b/tests/functional/const0.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/const1.asm b/tests/functional/const1.asm index 8f50ef1b9..c708b31ab 100644 --- a/tests/functional/const1.asm +++ b/tests/functional/const1.asm @@ -28,7 +28,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/const3.asm b/tests/functional/const3.asm index c2f386813..834221e3c 100644 --- a/tests/functional/const3.asm +++ b/tests/functional/const3.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _dgConnected: DEFW 0001h diff --git a/tests/functional/cpeq16.asm b/tests/functional/cpeq16.asm index dba683a95..40d803a43 100644 --- a/tests/functional/cpeq16.asm +++ b/tests/functional/cpeq16.asm @@ -37,7 +37,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "eq16.asm" - + __EQ16: ; Test if 16bit values HL == DE ; Returns result in A: 0 = False, FF = True xor a ; Reset carry flag @@ -45,9 +45,9 @@ __EQ16: ; Test if 16bit values HL == DE ret nz inc a ret - + #line 28 "cpeq16.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/declare0.asm b/tests/functional/declare0.asm index ec7fef5c3..9e4b187ec 100644 --- a/tests/functional/declare0.asm +++ b/tests/functional/declare0.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/defb.asm b/tests/functional/defb.asm index 12c58809a..7fd673aa7 100644 --- a/tests/functional/defb.asm +++ b/tests/functional/defb.asm @@ -29,7 +29,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/dimconst.asm b/tests/functional/dimconst.asm index 5ae6abc2f..0ee746293 100644 --- a/tests/functional/dimconst.asm +++ b/tests/functional/dimconst.asm @@ -44,7 +44,7 @@ _p__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: _Map: DEFB 00, 00 diff --git a/tests/functional/dimconst2.asm b/tests/functional/dimconst2.asm index d9eac9d13..6cd67a27a 100644 --- a/tests/functional/dimconst2.asm +++ b/tests/functional/dimconst2.asm @@ -45,7 +45,7 @@ _q__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: __LABEL0: DEFW __LABEL__Map diff --git a/tests/functional/dimconst2c.asm b/tests/functional/dimconst2c.asm index 310285840..c43c9d1ac 100644 --- a/tests/functional/dimconst2c.asm +++ b/tests/functional/dimconst2c.asm @@ -46,7 +46,7 @@ _q__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: _Map: DEFB 00 diff --git a/tests/functional/dimconst2d.asm b/tests/functional/dimconst2d.asm index 35a6bfd0a..a981f1038 100644 --- a/tests/functional/dimconst2d.asm +++ b/tests/functional/dimconst2d.asm @@ -44,7 +44,7 @@ _q__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: _Map: DEFB 01h diff --git a/tests/functional/dimconst2e.asm b/tests/functional/dimconst2e.asm index e1c5f1ea6..2303f7bb1 100644 --- a/tests/functional/dimconst2e.asm +++ b/tests/functional/dimconst2e.asm @@ -48,7 +48,7 @@ _q__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: _Map: DEFB 00 diff --git a/tests/functional/dimconst3.asm b/tests/functional/dimconst3.asm index bf384a91d..b542ff3f8 100644 --- a/tests/functional/dimconst3.asm +++ b/tests/functional/dimconst3.asm @@ -27,7 +27,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFW __LABEL__Map diff --git a/tests/functional/dimconst4.asm b/tests/functional/dimconst4.asm index 81a7d79c0..9f4e0db87 100644 --- a/tests/functional/dimconst4.asm +++ b/tests/functional/dimconst4.asm @@ -27,7 +27,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB (__LABEL__Map) & 0xFF diff --git a/tests/functional/dimconst4b.asm b/tests/functional/dimconst4b.asm index bf384a91d..b542ff3f8 100644 --- a/tests/functional/dimconst4b.asm +++ b/tests/functional/dimconst4b.asm @@ -27,7 +27,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFW __LABEL__Map diff --git a/tests/functional/dimconst4c.asm b/tests/functional/dimconst4c.asm index 8ee729da7..801ce20bd 100644 --- a/tests/functional/dimconst4c.asm +++ b/tests/functional/dimconst4c.asm @@ -27,7 +27,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFW ((__LABEL__Map) & 0xFFFFFFFF) & 0xFFFF diff --git a/tests/functional/dimconst5.asm b/tests/functional/dimconst5.asm index 99c83eb1c..5902a6cd6 100644 --- a/tests/functional/dimconst5.asm +++ b/tests/functional/dimconst5.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 0FEh diff --git a/tests/functional/dimconst6.asm b/tests/functional/dimconst6.asm index 00fcfa54a..9dbc122e7 100644 --- a/tests/functional/dimconst6.asm +++ b/tests/functional/dimconst6.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _Map: DEFB 34h diff --git a/tests/functional/div32.asm b/tests/functional/div32.asm index 97641dfcd..b98e9efa1 100644 --- a/tests/functional/div32.asm +++ b/tests/functional/div32.asm @@ -37,41 +37,41 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "negf.asm" - + #line 1 "u32tofreg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "u32tofreg.asm" __I8TOFREG: ld l, a @@ -80,35 +80,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -116,20 +116,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -137,46 +137,46 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 2 "negf.asm" #line 1 "ftou32reg.asm" - - - + + + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) PROC - + LOCAL __IS_FLOAT - + or a - jr nz, __IS_FLOAT + jr nz, __IS_FLOAT ; Here if it is a ZX ROM Integer - + ld h, c ld l, d ld a, e ; Takes sign: FF = -, 0 = + @@ -184,96 +184,96 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS inc a jp z, __NEG32 ; Negates if negative ret - + __IS_FLOAT: ; Jumps here if it is a true floating point number - ld h, e + ld h, e push hl ; Stores it for later (Contains Sign in H) - + push de push bc - + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + ;ld a, c ; Get exponent sub 128 ; Exponent -= 128 jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 - + __FTOU32REG_LOOP: exx ; Shift C'B' E'D' << 1, output bit stays in Carry sla d rl e rl b rl c - + exx ; Shift DEHL << 1, inserting the carry on the right rl l rl h rl e rl d - + djnz __FTOU32REG_LOOP - + __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative jp m, __NEG32 ; Negates DEHL - + ret - + ENDP - - + + __FTOU8: ; Converts float in C ED LH to Unsigned byte in A call __FTOU32REG ld a, l ret - + #line 3 "negf.asm" #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -289,30 +289,30 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 4 "negf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) - + ; All of them uses C EDHL registers as 1st paramter. ; For binary operators, the 2n operator must be pushed into the ; stack, in the order BC DE HL (B not used). ; ; Uses CALLEE convention ; ------------------------------------------------------------- - -__NEGF: ; A = -A + +__NEGF: ; A = -A call __FPSTACK_PUSH - + ; ------------- ROM NEGATE rst 28h defb 1Bh ; NEGF defb 38h; ; END CALC - + jp __FPSTACK_POP - - + + #line 28 "div32.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00 diff --git a/tests/functional/divf00.asm b/tests/functional/divf00.asm index b32c2d839..4ca99a357 100644 --- a/tests/functional/divf00.asm +++ b/tests/functional/divf00.asm @@ -35,40 +35,40 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "divf.asm" - + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -85,20 +85,20 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK jp __FPSTACK_PUSH #line 2 "divf.asm" #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -106,12 +106,12 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -119,34 +119,34 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "divf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) - + ; All of them uses C EDHL registers as 1st paramter. ; For binary operators, the 2n operator must be pushed into the ; stack, in the order BC DE HL (B not used). ; ; Uses CALLEE convention ; ------------------------------------------------------------- - + __DIVF: ; Division PROC LOCAL __DIVBYZERO LOCAL TMP, ERR_SP - + TMP EQU 23629 ;(DEST) ERR_SP EQU 23613 - + call __FPSTACK_PUSH2 - + ld hl, (ERR_SP) ld (TMP), hl ld hl, __DIVBYZERO @@ -154,26 +154,26 @@ __DIVF: ; Division ld hl, 0 add hl, sp ld (ERR_SP), hl - + ; ------------- ROM DIV rst 28h defb 01h ; EXCHANGE defb 05h ; DIV defb 38h; ; END CALC - + pop hl ld hl, (TMP) ld (ERR_SP), hl - + jp __FPSTACK_POP - + __DIVBYZERO: ld hl, (TMP) ld (ERR_SP), hl - + ld a, ERROR_NumberTooBig ld (ERR_NR), a - + ; Returns 0 on DIV BY ZERO error xor a ld b, a @@ -181,18 +181,18 @@ __DIVBYZERO: ld d, a ld e, a ret - + ENDP - + #line 26 "divf00.bas" #line 1 "pushf.asm" - - - ; Routine to push Float pointed by HL + + + ; Routine to push Float pointed by HL ; Into the stack. Notice that the hl points to the last ; byte of the FP number. ; Uses H'L' B'C' and D'E' to preserve ABCDEHL registers - + __FP_PUSH_REV: push hl exx @@ -213,11 +213,11 @@ __FP_PUSH_REV: push bc ; Return Address exx ret - - + + #line 27 "divf00.bas" #line 1 "storef.asm" - + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -225,7 +225,7 @@ __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory pop hl ; HL <- IX add hl, de ; HL <- IX + HL pop de - + __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register ex af, af' ld a, (hl) @@ -233,7 +233,7 @@ __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address ld h, (hl) ld l, a ; HL = (HL) ex af, af' - + __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), a inc hl @@ -245,9 +245,9 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL inc hl ld (hl), b ret - + #line 28 "divf00.bas" - + ZXBASIC_USER_DATA: _a: DEFB 80h diff --git a/tests/functional/divf01.asm b/tests/functional/divf01.asm index 9c2562bd2..af31893ed 100644 --- a/tests/functional/divf01.asm +++ b/tests/functional/divf01.asm @@ -39,40 +39,40 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "divf.asm" - + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -89,20 +89,20 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK jp __FPSTACK_PUSH #line 2 "divf.asm" #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -110,12 +110,12 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -123,34 +123,34 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "divf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) - + ; All of them uses C EDHL registers as 1st paramter. ; For binary operators, the 2n operator must be pushed into the ; stack, in the order BC DE HL (B not used). ; ; Uses CALLEE convention ; ------------------------------------------------------------- - + __DIVF: ; Division PROC LOCAL __DIVBYZERO LOCAL TMP, ERR_SP - + TMP EQU 23629 ;(DEST) ERR_SP EQU 23613 - + call __FPSTACK_PUSH2 - + ld hl, (ERR_SP) ld (TMP), hl ld hl, __DIVBYZERO @@ -158,26 +158,26 @@ __DIVF: ; Division ld hl, 0 add hl, sp ld (ERR_SP), hl - + ; ------------- ROM DIV rst 28h defb 01h ; EXCHANGE defb 05h ; DIV defb 38h; ; END CALC - + pop hl ld hl, (TMP) ld (ERR_SP), hl - + jp __FPSTACK_POP - + __DIVBYZERO: ld hl, (TMP) ld (ERR_SP), hl - + ld a, ERROR_NumberTooBig ld (ERR_NR), a - + ; Returns 0 on DIV BY ZERO error xor a ld b, a @@ -185,12 +185,12 @@ __DIVBYZERO: ld d, a ld e, a ret - + ENDP - + #line 30 "divf01.bas" #line 1 "storef.asm" - + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -198,7 +198,7 @@ __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory pop hl ; HL <- IX add hl, de ; HL <- IX + HL pop de - + __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register ex af, af' ld a, (hl) @@ -206,7 +206,7 @@ __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address ld h, (hl) ld l, a ; HL = (HL) ex af, af' - + __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), a inc hl @@ -218,9 +218,9 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL inc hl ld (hl), b ret - + #line 31 "divf01.bas" - + ZXBASIC_USER_DATA: _a: DEFB 80h diff --git a/tests/functional/divf16.asm b/tests/functional/divf16.asm index 27e8e9581..047aba3d5 100644 --- a/tests/functional/divf16.asm +++ b/tests/functional/divf16.asm @@ -94,43 +94,43 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "divf16.asm" - + #line 1 "div32.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "div32.asm" - + ; --------------------------------------------------------- __DIVU32: ; 32 bit unsigned division ; DEHL = Dividend, Stack Top = Divisor @@ -142,7 +142,7 @@ __DIVU32: ; 32 bit unsigned division pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + __DIVU32START: ; Performs D'E'H'L' / HLDE ; Now switch to DIVIDEND = B'C'BC / DIVISOR = D'E'DE (A / B) push de ; push Lowpart(Q) @@ -158,9 +158,9 @@ __DIVU32START: ; Performs D'E'H'L' / HLDE exx pop bc ; Pop HightPart(B) => B = B'C'BC exx - + ld a, 32 ; Loop count - + __DIV32LOOP: sll c ; B'C'BC << 1 ; Output most left bit to carry rl b @@ -168,29 +168,29 @@ __DIV32LOOP: rl c rl b exx - + adc hl, hl exx adc hl, hl exx - + sbc hl,de exx sbc hl,de exx jp nc, __DIV32NOADD ; use JP inside a loop for being faster - + add hl, de exx adc hl, de exx dec bc - + __DIV32NOADD: dec a jp nz, __DIV32LOOP ; use JP inside a loop for being faster ; At this point, quotient is stored in B'C'BC and the reminder in H'L'HL - + push hl exx pop de @@ -200,34 +200,34 @@ __DIV32NOADD: pop de ; DE = B'C' ld h, b ld l, c ; DEHL = quotient D'E'H'L' = Modulus - + ret ; DEHL = quotient, D'E'H'L' = Modulus - - - + + + __MODU32: ; 32 bit modulus for 32bit unsigned division ; DEHL = Dividend, Stack Top = Divisor (DE, HL) - + exx pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + call __DIVU32START ; At return, modulus is at D'E'H'L' - + __MODU32START: - + exx push de push hl - - exx + + exx pop hl pop de - + ret - - + + __DIVI32: ; 32 bit signed division ; DEHL = Dividend, Stack Top = Divisor ; A = Dividend, B = Divisor => A / B @@ -235,126 +235,126 @@ __DIVI32: ; 32 bit signed division pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + __DIVI32START: exx ld a, d ; Save sign ex af, af' bit 7, d ; Negative? call nz, __NEG32 ; Negates DEHL - + exx ; Now works with H'L'D'E' ex af, af' xor h ex af, af' ; Stores sign of the result for later - + bit 7, h ; Negative? ex de, hl ; HLDE = DEHL call nz, __NEG32 - ex de, hl - + ex de, hl + call __DIVU32START ex af, af' ; Recovers sign and 128 ; positive? ret z - + jp __NEG32 ; Negates DEHL and returns from there - - + + __MODI32: ; 32bits signed division modulus exx pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + call __DIVI32START - jp __MODU32START - + jp __MODU32START + #line 2 "divf16.asm" - - -__DIVF16: ; 16.16 Fixed point Division (signed) - - ; DE.HL = Dividend, Stack Top = Divisor - ; A = Dividend, B = Divisor => A / B - exx - pop hl ; return address - pop de ; low part - ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - ex de, hl ; D'E'.H'L' Dividend - -__DIVF16START: ; FAST Entry: DEHL => Dividend, D'E'H'L' => Divisor - ld a, d ; Save sign - ex af, af' - bit 7, d ; Negative? - call nz, __NEG32 ; Negates DEHL - - exx ; Now works with D'E'.H'L' - ex af, af' - xor d - ex af, af' ; Stores sign of the result for later - - bit 7, d ; Negative? - call nz, __NEG32 - exx ; Now we have DE.HL => Dividend - - ld b, 16 - -__SHIFTALOOP: ; Tries to shift Dividend to the left - bit 7, d - jp nz, __SHIFTB - add hl, hl - ex de, hl - adc hl, hl - ex de, hl - djnz __SHIFTALOOP - jp __DOF16_DIVRDY - -__SHIFTB: ; Cannot shift Dividend more to the left, try to shift Divisor to the right - ld a, b - exx - ld b, a - ; Divisor is in DEHL -__SHIFTBLOOP: - bit 1, l - jp nz, __DOF16_DIVIDE - sra d - rr e - rr h - rr l - djnz __SHIFTBLOOP - -__DOF16_DIVIDE: - ld a, b - exx - ld b, a - -__DOF16_DIVRDY: - exx - ex de, hl - push bc - call __DIVU32START - pop bc - - xor a - or b - jp z, __ENDF16DIV - -__SHIFTCLOOP: - add hl, hl ; Shift DECIMAL PART << 1 - ex de, hl - adc hl, hl ; Shift INTEGER PART << 1 Plus Carry - ex de, hl - djnz __SHIFTCLOOP - -__ENDF16DIV: ; Put the sign on the result - ex af, af' ; Recovers sign - and 128 ; positive? - ret z - jp __NEG32 ; Negates DEHL and returns from there - + + +__DIVF16: ; 16.16 Fixed point Division (signed) + + ; DE.HL = Dividend, Stack Top = Divisor + ; A = Dividend, B = Divisor => A / B + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + ex de, hl ; D'E'.H'L' Dividend + +__DIVF16START: ; FAST Entry: DEHL => Dividend, D'E'H'L' => Divisor + ld a, d ; Save sign + ex af, af' + bit 7, d ; Negative? + call nz, __NEG32 ; Negates DEHL + + exx ; Now works with D'E'.H'L' + ex af, af' + xor d + ex af, af' ; Stores sign of the result for later + + bit 7, d ; Negative? + call nz, __NEG32 + exx ; Now we have DE.HL => Dividend + + ld b, 16 + +__SHIFTALOOP: ; Tries to shift Dividend to the left + bit 7, d + jp nz, __SHIFTB + add hl, hl + ex de, hl + adc hl, hl + ex de, hl + djnz __SHIFTALOOP + jp __DOF16_DIVRDY + +__SHIFTB: ; Cannot shift Dividend more to the left, try to shift Divisor to the right + ld a, b + exx + ld b, a + ; Divisor is in DEHL +__SHIFTBLOOP: + bit 1, l + jp nz, __DOF16_DIVIDE + sra d + rr e + rr h + rr l + djnz __SHIFTBLOOP + +__DOF16_DIVIDE: + ld a, b + exx + ld b, a + +__DOF16_DIVRDY: + exx + ex de, hl + push bc + call __DIVU32START + pop bc + + xor a + or b + jp z, __ENDF16DIV + +__SHIFTCLOOP: + add hl, hl ; Shift DECIMAL PART << 1 + ex de, hl + adc hl, hl ; Shift INTEGER PART << 1 Plus Carry + ex de, hl + djnz __SHIFTCLOOP + +__ENDF16DIV: ; Put the sign on the result + ex af, af' ; Recovers sign + and 128 ; positive? + ret z + jp __NEG32 ; Negates DEHL and returns from there + #line 85 "divf16.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00 diff --git a/tests/functional/divf16a.asm b/tests/functional/divf16a.asm index 84615fff7..64324b919 100644 --- a/tests/functional/divf16a.asm +++ b/tests/functional/divf16a.asm @@ -41,43 +41,43 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "divf16.asm" - + #line 1 "div32.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "div32.asm" - + ; --------------------------------------------------------- __DIVU32: ; 32 bit unsigned division ; DEHL = Dividend, Stack Top = Divisor @@ -89,7 +89,7 @@ __DIVU32: ; 32 bit unsigned division pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + __DIVU32START: ; Performs D'E'H'L' / HLDE ; Now switch to DIVIDEND = B'C'BC / DIVISOR = D'E'DE (A / B) push de ; push Lowpart(Q) @@ -105,9 +105,9 @@ __DIVU32START: ; Performs D'E'H'L' / HLDE exx pop bc ; Pop HightPart(B) => B = B'C'BC exx - + ld a, 32 ; Loop count - + __DIV32LOOP: sll c ; B'C'BC << 1 ; Output most left bit to carry rl b @@ -115,29 +115,29 @@ __DIV32LOOP: rl c rl b exx - + adc hl, hl exx adc hl, hl exx - + sbc hl,de exx sbc hl,de exx jp nc, __DIV32NOADD ; use JP inside a loop for being faster - + add hl, de exx adc hl, de exx dec bc - + __DIV32NOADD: dec a jp nz, __DIV32LOOP ; use JP inside a loop for being faster ; At this point, quotient is stored in B'C'BC and the reminder in H'L'HL - + push hl exx pop de @@ -147,34 +147,34 @@ __DIV32NOADD: pop de ; DE = B'C' ld h, b ld l, c ; DEHL = quotient D'E'H'L' = Modulus - + ret ; DEHL = quotient, D'E'H'L' = Modulus - - - + + + __MODU32: ; 32 bit modulus for 32bit unsigned division ; DEHL = Dividend, Stack Top = Divisor (DE, HL) - + exx pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + call __DIVU32START ; At return, modulus is at D'E'H'L' - + __MODU32START: - + exx push de push hl - - exx + + exx pop hl pop de - + ret - - + + __DIVI32: ; 32 bit signed division ; DEHL = Dividend, Stack Top = Divisor ; A = Dividend, B = Divisor => A / B @@ -182,126 +182,126 @@ __DIVI32: ; 32 bit signed division pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + __DIVI32START: exx ld a, d ; Save sign ex af, af' bit 7, d ; Negative? call nz, __NEG32 ; Negates DEHL - + exx ; Now works with H'L'D'E' ex af, af' xor h ex af, af' ; Stores sign of the result for later - + bit 7, h ; Negative? ex de, hl ; HLDE = DEHL call nz, __NEG32 - ex de, hl - + ex de, hl + call __DIVU32START ex af, af' ; Recovers sign and 128 ; positive? ret z - + jp __NEG32 ; Negates DEHL and returns from there - - + + __MODI32: ; 32bits signed division modulus exx pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + call __DIVI32START - jp __MODU32START - + jp __MODU32START + #line 2 "divf16.asm" - - -__DIVF16: ; 16.16 Fixed point Division (signed) - - ; DE.HL = Dividend, Stack Top = Divisor - ; A = Dividend, B = Divisor => A / B - exx - pop hl ; return address - pop de ; low part - ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - ex de, hl ; D'E'.H'L' Dividend - -__DIVF16START: ; FAST Entry: DEHL => Dividend, D'E'H'L' => Divisor - ld a, d ; Save sign - ex af, af' - bit 7, d ; Negative? - call nz, __NEG32 ; Negates DEHL - - exx ; Now works with D'E'.H'L' - ex af, af' - xor d - ex af, af' ; Stores sign of the result for later - - bit 7, d ; Negative? - call nz, __NEG32 - exx ; Now we have DE.HL => Dividend - - ld b, 16 - -__SHIFTALOOP: ; Tries to shift Dividend to the left - bit 7, d - jp nz, __SHIFTB - add hl, hl - ex de, hl - adc hl, hl - ex de, hl - djnz __SHIFTALOOP - jp __DOF16_DIVRDY - -__SHIFTB: ; Cannot shift Dividend more to the left, try to shift Divisor to the right - ld a, b - exx - ld b, a - ; Divisor is in DEHL -__SHIFTBLOOP: - bit 1, l - jp nz, __DOF16_DIVIDE - sra d - rr e - rr h - rr l - djnz __SHIFTBLOOP - -__DOF16_DIVIDE: - ld a, b - exx - ld b, a - -__DOF16_DIVRDY: - exx - ex de, hl - push bc - call __DIVU32START - pop bc - - xor a - or b - jp z, __ENDF16DIV - -__SHIFTCLOOP: - add hl, hl ; Shift DECIMAL PART << 1 - ex de, hl - adc hl, hl ; Shift INTEGER PART << 1 Plus Carry - ex de, hl - djnz __SHIFTCLOOP - -__ENDF16DIV: ; Put the sign on the result - ex af, af' ; Recovers sign - and 128 ; positive? - ret z - jp __NEG32 ; Negates DEHL and returns from there - + + +__DIVF16: ; 16.16 Fixed point Division (signed) + + ; DE.HL = Dividend, Stack Top = Divisor + ; A = Dividend, B = Divisor => A / B + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + ex de, hl ; D'E'.H'L' Dividend + +__DIVF16START: ; FAST Entry: DEHL => Dividend, D'E'H'L' => Divisor + ld a, d ; Save sign + ex af, af' + bit 7, d ; Negative? + call nz, __NEG32 ; Negates DEHL + + exx ; Now works with D'E'.H'L' + ex af, af' + xor d + ex af, af' ; Stores sign of the result for later + + bit 7, d ; Negative? + call nz, __NEG32 + exx ; Now we have DE.HL => Dividend + + ld b, 16 + +__SHIFTALOOP: ; Tries to shift Dividend to the left + bit 7, d + jp nz, __SHIFTB + add hl, hl + ex de, hl + adc hl, hl + ex de, hl + djnz __SHIFTALOOP + jp __DOF16_DIVRDY + +__SHIFTB: ; Cannot shift Dividend more to the left, try to shift Divisor to the right + ld a, b + exx + ld b, a + ; Divisor is in DEHL +__SHIFTBLOOP: + bit 1, l + jp nz, __DOF16_DIVIDE + sra d + rr e + rr h + rr l + djnz __SHIFTBLOOP + +__DOF16_DIVIDE: + ld a, b + exx + ld b, a + +__DOF16_DIVRDY: + exx + ex de, hl + push bc + call __DIVU32START + pop bc + + xor a + or b + jp z, __ENDF16DIV + +__SHIFTCLOOP: + add hl, hl ; Shift DECIMAL PART << 1 + ex de, hl + adc hl, hl ; Shift INTEGER PART << 1 Plus Carry + ex de, hl + djnz __SHIFTCLOOP + +__ENDF16DIV: ; Put the sign on the result + ex af, af' ; Recovers sign + and 128 ; positive? + ret z + jp __NEG32 ; Negates DEHL and returns from there + #line 32 "divf16a.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00 diff --git a/tests/functional/divf16b.asm b/tests/functional/divf16b.asm index 4ed8f2f5c..ee68c738c 100644 --- a/tests/functional/divf16b.asm +++ b/tests/functional/divf16b.asm @@ -51,43 +51,43 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "divf16.asm" - + #line 1 "div32.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "div32.asm" - + ; --------------------------------------------------------- __DIVU32: ; 32 bit unsigned division ; DEHL = Dividend, Stack Top = Divisor @@ -99,7 +99,7 @@ __DIVU32: ; 32 bit unsigned division pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + __DIVU32START: ; Performs D'E'H'L' / HLDE ; Now switch to DIVIDEND = B'C'BC / DIVISOR = D'E'DE (A / B) push de ; push Lowpart(Q) @@ -115,9 +115,9 @@ __DIVU32START: ; Performs D'E'H'L' / HLDE exx pop bc ; Pop HightPart(B) => B = B'C'BC exx - + ld a, 32 ; Loop count - + __DIV32LOOP: sll c ; B'C'BC << 1 ; Output most left bit to carry rl b @@ -125,29 +125,29 @@ __DIV32LOOP: rl c rl b exx - + adc hl, hl exx adc hl, hl exx - + sbc hl,de exx sbc hl,de exx jp nc, __DIV32NOADD ; use JP inside a loop for being faster - + add hl, de exx adc hl, de exx dec bc - + __DIV32NOADD: dec a jp nz, __DIV32LOOP ; use JP inside a loop for being faster ; At this point, quotient is stored in B'C'BC and the reminder in H'L'HL - + push hl exx pop de @@ -157,34 +157,34 @@ __DIV32NOADD: pop de ; DE = B'C' ld h, b ld l, c ; DEHL = quotient D'E'H'L' = Modulus - + ret ; DEHL = quotient, D'E'H'L' = Modulus - - - + + + __MODU32: ; 32 bit modulus for 32bit unsigned division ; DEHL = Dividend, Stack Top = Divisor (DE, HL) - + exx pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + call __DIVU32START ; At return, modulus is at D'E'H'L' - + __MODU32START: - + exx push de push hl - - exx + + exx pop hl pop de - + ret - - + + __DIVI32: ; 32 bit signed division ; DEHL = Dividend, Stack Top = Divisor ; A = Dividend, B = Divisor => A / B @@ -192,126 +192,126 @@ __DIVI32: ; 32 bit signed division pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + __DIVI32START: exx ld a, d ; Save sign ex af, af' bit 7, d ; Negative? call nz, __NEG32 ; Negates DEHL - + exx ; Now works with H'L'D'E' ex af, af' xor h ex af, af' ; Stores sign of the result for later - + bit 7, h ; Negative? ex de, hl ; HLDE = DEHL call nz, __NEG32 - ex de, hl - + ex de, hl + call __DIVU32START ex af, af' ; Recovers sign and 128 ; positive? ret z - + jp __NEG32 ; Negates DEHL and returns from there - - + + __MODI32: ; 32bits signed division modulus exx pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + call __DIVI32START - jp __MODU32START - + jp __MODU32START + #line 2 "divf16.asm" - - -__DIVF16: ; 16.16 Fixed point Division (signed) - - ; DE.HL = Dividend, Stack Top = Divisor - ; A = Dividend, B = Divisor => A / B - exx - pop hl ; return address - pop de ; low part - ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - ex de, hl ; D'E'.H'L' Dividend - -__DIVF16START: ; FAST Entry: DEHL => Dividend, D'E'H'L' => Divisor - ld a, d ; Save sign - ex af, af' - bit 7, d ; Negative? - call nz, __NEG32 ; Negates DEHL - - exx ; Now works with D'E'.H'L' - ex af, af' - xor d - ex af, af' ; Stores sign of the result for later - - bit 7, d ; Negative? - call nz, __NEG32 - exx ; Now we have DE.HL => Dividend - - ld b, 16 - -__SHIFTALOOP: ; Tries to shift Dividend to the left - bit 7, d - jp nz, __SHIFTB - add hl, hl - ex de, hl - adc hl, hl - ex de, hl - djnz __SHIFTALOOP - jp __DOF16_DIVRDY - -__SHIFTB: ; Cannot shift Dividend more to the left, try to shift Divisor to the right - ld a, b - exx - ld b, a - ; Divisor is in DEHL -__SHIFTBLOOP: - bit 1, l - jp nz, __DOF16_DIVIDE - sra d - rr e - rr h - rr l - djnz __SHIFTBLOOP - -__DOF16_DIVIDE: - ld a, b - exx - ld b, a - -__DOF16_DIVRDY: - exx - ex de, hl - push bc - call __DIVU32START - pop bc - - xor a - or b - jp z, __ENDF16DIV - -__SHIFTCLOOP: - add hl, hl ; Shift DECIMAL PART << 1 - ex de, hl - adc hl, hl ; Shift INTEGER PART << 1 Plus Carry - ex de, hl - djnz __SHIFTCLOOP - -__ENDF16DIV: ; Put the sign on the result - ex af, af' ; Recovers sign - and 128 ; positive? - ret z - jp __NEG32 ; Negates DEHL and returns from there - + + +__DIVF16: ; 16.16 Fixed point Division (signed) + + ; DE.HL = Dividend, Stack Top = Divisor + ; A = Dividend, B = Divisor => A / B + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + ex de, hl ; D'E'.H'L' Dividend + +__DIVF16START: ; FAST Entry: DEHL => Dividend, D'E'H'L' => Divisor + ld a, d ; Save sign + ex af, af' + bit 7, d ; Negative? + call nz, __NEG32 ; Negates DEHL + + exx ; Now works with D'E'.H'L' + ex af, af' + xor d + ex af, af' ; Stores sign of the result for later + + bit 7, d ; Negative? + call nz, __NEG32 + exx ; Now we have DE.HL => Dividend + + ld b, 16 + +__SHIFTALOOP: ; Tries to shift Dividend to the left + bit 7, d + jp nz, __SHIFTB + add hl, hl + ex de, hl + adc hl, hl + ex de, hl + djnz __SHIFTALOOP + jp __DOF16_DIVRDY + +__SHIFTB: ; Cannot shift Dividend more to the left, try to shift Divisor to the right + ld a, b + exx + ld b, a + ; Divisor is in DEHL +__SHIFTBLOOP: + bit 1, l + jp nz, __DOF16_DIVIDE + sra d + rr e + rr h + rr l + djnz __SHIFTBLOOP + +__DOF16_DIVIDE: + ld a, b + exx + ld b, a + +__DOF16_DIVRDY: + exx + ex de, hl + push bc + call __DIVU32START + pop bc + + xor a + or b + jp z, __ENDF16DIV + +__SHIFTCLOOP: + add hl, hl ; Shift DECIMAL PART << 1 + ex de, hl + adc hl, hl ; Shift INTEGER PART << 1 Plus Carry + ex de, hl + djnz __SHIFTCLOOP + +__ENDF16DIV: ; Put the sign on the result + ex af, af' ; Recovers sign + and 128 ; positive? + ret z + jp __NEG32 ; Negates DEHL and returns from there + #line 42 "divf16b.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00 diff --git a/tests/functional/divf16c.asm b/tests/functional/divf16c.asm index 40875bd66..fa311b530 100644 --- a/tests/functional/divf16c.asm +++ b/tests/functional/divf16c.asm @@ -77,43 +77,43 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "divf16.asm" - + #line 1 "div32.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "div32.asm" - + ; --------------------------------------------------------- __DIVU32: ; 32 bit unsigned division ; DEHL = Dividend, Stack Top = Divisor @@ -125,7 +125,7 @@ __DIVU32: ; 32 bit unsigned division pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + __DIVU32START: ; Performs D'E'H'L' / HLDE ; Now switch to DIVIDEND = B'C'BC / DIVISOR = D'E'DE (A / B) push de ; push Lowpart(Q) @@ -141,9 +141,9 @@ __DIVU32START: ; Performs D'E'H'L' / HLDE exx pop bc ; Pop HightPart(B) => B = B'C'BC exx - + ld a, 32 ; Loop count - + __DIV32LOOP: sll c ; B'C'BC << 1 ; Output most left bit to carry rl b @@ -151,29 +151,29 @@ __DIV32LOOP: rl c rl b exx - + adc hl, hl exx adc hl, hl exx - + sbc hl,de exx sbc hl,de exx jp nc, __DIV32NOADD ; use JP inside a loop for being faster - + add hl, de exx adc hl, de exx dec bc - + __DIV32NOADD: dec a jp nz, __DIV32LOOP ; use JP inside a loop for being faster ; At this point, quotient is stored in B'C'BC and the reminder in H'L'HL - + push hl exx pop de @@ -183,34 +183,34 @@ __DIV32NOADD: pop de ; DE = B'C' ld h, b ld l, c ; DEHL = quotient D'E'H'L' = Modulus - + ret ; DEHL = quotient, D'E'H'L' = Modulus - - - + + + __MODU32: ; 32 bit modulus for 32bit unsigned division ; DEHL = Dividend, Stack Top = Divisor (DE, HL) - + exx pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + call __DIVU32START ; At return, modulus is at D'E'H'L' - + __MODU32START: - + exx push de push hl - - exx + + exx pop hl pop de - + ret - - + + __DIVI32: ; 32 bit signed division ; DEHL = Dividend, Stack Top = Divisor ; A = Dividend, B = Divisor => A / B @@ -218,130 +218,130 @@ __DIVI32: ; 32 bit signed division pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + __DIVI32START: exx ld a, d ; Save sign ex af, af' bit 7, d ; Negative? call nz, __NEG32 ; Negates DEHL - + exx ; Now works with H'L'D'E' ex af, af' xor h ex af, af' ; Stores sign of the result for later - + bit 7, h ; Negative? ex de, hl ; HLDE = DEHL call nz, __NEG32 - ex de, hl - + ex de, hl + call __DIVU32START ex af, af' ; Recovers sign and 128 ; positive? ret z - + jp __NEG32 ; Negates DEHL and returns from there - - + + __MODI32: ; 32bits signed division modulus exx pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + call __DIVI32START - jp __MODU32START - + jp __MODU32START + #line 2 "divf16.asm" - - -__DIVF16: ; 16.16 Fixed point Division (signed) - - ; DE.HL = Dividend, Stack Top = Divisor - ; A = Dividend, B = Divisor => A / B - exx - pop hl ; return address - pop de ; low part - ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - ex de, hl ; D'E'.H'L' Dividend - -__DIVF16START: ; FAST Entry: DEHL => Dividend, D'E'H'L' => Divisor - ld a, d ; Save sign - ex af, af' - bit 7, d ; Negative? - call nz, __NEG32 ; Negates DEHL - - exx ; Now works with D'E'.H'L' - ex af, af' - xor d - ex af, af' ; Stores sign of the result for later - - bit 7, d ; Negative? - call nz, __NEG32 - exx ; Now we have DE.HL => Dividend - - ld b, 16 - -__SHIFTALOOP: ; Tries to shift Dividend to the left - bit 7, d - jp nz, __SHIFTB - add hl, hl - ex de, hl - adc hl, hl - ex de, hl - djnz __SHIFTALOOP - jp __DOF16_DIVRDY - -__SHIFTB: ; Cannot shift Dividend more to the left, try to shift Divisor to the right - ld a, b - exx - ld b, a - ; Divisor is in DEHL -__SHIFTBLOOP: - bit 1, l - jp nz, __DOF16_DIVIDE - sra d - rr e - rr h - rr l - djnz __SHIFTBLOOP - -__DOF16_DIVIDE: - ld a, b - exx - ld b, a - -__DOF16_DIVRDY: - exx - ex de, hl - push bc - call __DIVU32START - pop bc - - xor a - or b - jp z, __ENDF16DIV - -__SHIFTCLOOP: - add hl, hl ; Shift DECIMAL PART << 1 - ex de, hl - adc hl, hl ; Shift INTEGER PART << 1 Plus Carry - ex de, hl - djnz __SHIFTCLOOP - -__ENDF16DIV: ; Put the sign on the result - ex af, af' ; Recovers sign - and 128 ; positive? - ret z - jp __NEG32 ; Negates DEHL and returns from there - + + +__DIVF16: ; 16.16 Fixed point Division (signed) + + ; DE.HL = Dividend, Stack Top = Divisor + ; A = Dividend, B = Divisor => A / B + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + ex de, hl ; D'E'.H'L' Dividend + +__DIVF16START: ; FAST Entry: DEHL => Dividend, D'E'H'L' => Divisor + ld a, d ; Save sign + ex af, af' + bit 7, d ; Negative? + call nz, __NEG32 ; Negates DEHL + + exx ; Now works with D'E'.H'L' + ex af, af' + xor d + ex af, af' ; Stores sign of the result for later + + bit 7, d ; Negative? + call nz, __NEG32 + exx ; Now we have DE.HL => Dividend + + ld b, 16 + +__SHIFTALOOP: ; Tries to shift Dividend to the left + bit 7, d + jp nz, __SHIFTB + add hl, hl + ex de, hl + adc hl, hl + ex de, hl + djnz __SHIFTALOOP + jp __DOF16_DIVRDY + +__SHIFTB: ; Cannot shift Dividend more to the left, try to shift Divisor to the right + ld a, b + exx + ld b, a + ; Divisor is in DEHL +__SHIFTBLOOP: + bit 1, l + jp nz, __DOF16_DIVIDE + sra d + rr e + rr h + rr l + djnz __SHIFTBLOOP + +__DOF16_DIVIDE: + ld a, b + exx + ld b, a + +__DOF16_DIVRDY: + exx + ex de, hl + push bc + call __DIVU32START + pop bc + + xor a + or b + jp z, __ENDF16DIV + +__SHIFTCLOOP: + add hl, hl ; Shift DECIMAL PART << 1 + ex de, hl + adc hl, hl ; Shift INTEGER PART << 1 Plus Carry + ex de, hl + djnz __SHIFTCLOOP + +__ENDF16DIV: ; Put the sign on the result + ex af, af' ; Recovers sign + and 128 ; positive? + ret z + jp __NEG32 ; Negates DEHL and returns from there + #line 68 "divf16c.bas" #line 1 "swap32.asm" - + ; Exchanges current DE HL with the ; ones in the stack - + __SWAP32: pop bc ; Return address ex (sp), hl @@ -354,9 +354,9 @@ __SWAP32: inc sp push bc ret - + #line 69 "divf16c.bas" - + ZXBASIC_USER_DATA: _level: DEFB 00h diff --git a/tests/functional/divi16a.asm b/tests/functional/divi16a.asm index 044265d25..7fd7359f6 100644 --- a/tests/functional/divi16a.asm +++ b/tests/functional/divi16a.asm @@ -33,17 +33,17 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div16.asm" - - ; 16 bit division and modulo functions + + ; 16 bit division and modulo functions ; for both signed and unsigned values - + #line 1 "neg16.asm" - + ; Negates HL value (16 bit) __ABS16: bit 7, h ret z - + __NEGHL: ld a, l ; HL = -HL cpl @@ -53,23 +53,23 @@ __NEGHL: ld h, a inc hl ret - + #line 5 "div16.asm" - + __DIVU16: ; 16 bit unsigned division ; HL = Dividend, Stack Top = Divisor - + ; -- OBSOLETE ; Now uses FASTCALL convention ; ex de, hl ; pop hl ; Return address ; ex (sp), hl ; CALLEE Convention - + __DIVU16_FAST: ld a, h ld c, l ld hl, 0 ld b, 16 - + __DIV16LOOP: sll c rla @@ -78,46 +78,46 @@ __DIV16LOOP: jr nc, __DIV16NOADD add hl,de dec c - + __DIV16NOADD: djnz __DIV16LOOP - + ex de, hl ld h, a ld l, c - + ret ; HL = quotient, DE = Mudulus - - - + + + __MODU16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVU16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - - + + __DIVI16: ; 16 bit signed division ; --- The following is OBSOLETE --- ; ex de, hl ; pop hl ; ex (sp), hl ; CALLEE Convention - + __DIVI16_FAST: ld a, d xor h ex af, af' ; BIT 7 of a contains result - + bit 7, d ; DE is negative? - jr z, __DIVI16A - + jr z, __DIVI16A + ld a, e ; DE = -DE cpl ld e, a @@ -125,35 +125,35 @@ __DIVI16_FAST: cpl ld d, a inc de - + __DIVI16A: bit 7, h ; HL is negative? call nz, __NEGHL - + __DIVI16B: call __DIVU16_FAST ex af, af' - - or a + + or a ret p ; return if positive jp __NEGHL - - + + __MODI16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVI16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - + #line 24 "divi16a.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/divi16b.asm b/tests/functional/divi16b.asm index 1741ee84f..1098b4d3e 100644 --- a/tests/functional/divi16b.asm +++ b/tests/functional/divi16b.asm @@ -40,17 +40,17 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div16.asm" - - ; 16 bit division and modulo functions + + ; 16 bit division and modulo functions ; for both signed and unsigned values - + #line 1 "neg16.asm" - + ; Negates HL value (16 bit) __ABS16: bit 7, h ret z - + __NEGHL: ld a, l ; HL = -HL cpl @@ -60,23 +60,23 @@ __NEGHL: ld h, a inc hl ret - + #line 5 "div16.asm" - + __DIVU16: ; 16 bit unsigned division ; HL = Dividend, Stack Top = Divisor - + ; -- OBSOLETE ; Now uses FASTCALL convention ; ex de, hl ; pop hl ; Return address ; ex (sp), hl ; CALLEE Convention - + __DIVU16_FAST: ld a, h ld c, l ld hl, 0 ld b, 16 - + __DIV16LOOP: sll c rla @@ -85,46 +85,46 @@ __DIV16LOOP: jr nc, __DIV16NOADD add hl,de dec c - + __DIV16NOADD: djnz __DIV16LOOP - + ex de, hl ld h, a ld l, c - + ret ; HL = quotient, DE = Mudulus - - - + + + __MODU16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVU16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - - + + __DIVI16: ; 16 bit signed division ; --- The following is OBSOLETE --- ; ex de, hl ; pop hl ; ex (sp), hl ; CALLEE Convention - + __DIVI16_FAST: ld a, d xor h ex af, af' ; BIT 7 of a contains result - + bit 7, d ; DE is negative? - jr z, __DIVI16A - + jr z, __DIVI16A + ld a, e ; DE = -DE cpl ld e, a @@ -132,35 +132,35 @@ __DIVI16_FAST: cpl ld d, a inc de - + __DIVI16A: bit 7, h ; HL is negative? call nz, __NEGHL - + __DIVI16B: call __DIVU16_FAST ex af, af' - - or a + + or a ret p ; return if positive jp __NEGHL - - + + __MODI16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVI16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - + #line 31 "divi16b.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/divi32c.asm b/tests/functional/divi32c.asm index 642c4fb77..ba8085fcb 100644 --- a/tests/functional/divi32c.asm +++ b/tests/functional/divi32c.asm @@ -80,41 +80,41 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div32.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "div32.asm" - + ; --------------------------------------------------------- __DIVU32: ; 32 bit unsigned division ; DEHL = Dividend, Stack Top = Divisor @@ -126,7 +126,7 @@ __DIVU32: ; 32 bit unsigned division pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + __DIVU32START: ; Performs D'E'H'L' / HLDE ; Now switch to DIVIDEND = B'C'BC / DIVISOR = D'E'DE (A / B) push de ; push Lowpart(Q) @@ -142,9 +142,9 @@ __DIVU32START: ; Performs D'E'H'L' / HLDE exx pop bc ; Pop HightPart(B) => B = B'C'BC exx - + ld a, 32 ; Loop count - + __DIV32LOOP: sll c ; B'C'BC << 1 ; Output most left bit to carry rl b @@ -152,29 +152,29 @@ __DIV32LOOP: rl c rl b exx - + adc hl, hl exx adc hl, hl exx - + sbc hl,de exx sbc hl,de exx jp nc, __DIV32NOADD ; use JP inside a loop for being faster - + add hl, de exx adc hl, de exx dec bc - + __DIV32NOADD: dec a jp nz, __DIV32LOOP ; use JP inside a loop for being faster ; At this point, quotient is stored in B'C'BC and the reminder in H'L'HL - + push hl exx pop de @@ -184,34 +184,34 @@ __DIV32NOADD: pop de ; DE = B'C' ld h, b ld l, c ; DEHL = quotient D'E'H'L' = Modulus - + ret ; DEHL = quotient, D'E'H'L' = Modulus - - - + + + __MODU32: ; 32 bit modulus for 32bit unsigned division ; DEHL = Dividend, Stack Top = Divisor (DE, HL) - + exx pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + call __DIVU32START ; At return, modulus is at D'E'H'L' - + __MODU32START: - + exx push de push hl - - exx + + exx pop hl pop de - + ret - - + + __DIVI32: ; 32 bit signed division ; DEHL = Dividend, Stack Top = Divisor ; A = Dividend, B = Divisor => A / B @@ -219,47 +219,47 @@ __DIVI32: ; 32 bit signed division pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + __DIVI32START: exx ld a, d ; Save sign ex af, af' bit 7, d ; Negative? call nz, __NEG32 ; Negates DEHL - + exx ; Now works with H'L'D'E' ex af, af' xor h ex af, af' ; Stores sign of the result for later - + bit 7, h ; Negative? ex de, hl ; HLDE = DEHL call nz, __NEG32 - ex de, hl - + ex de, hl + call __DIVU32START ex af, af' ; Recovers sign and 128 ; positive? ret z - + jp __NEG32 ; Negates DEHL and returns from there - - + + __MODI32: ; 32bits signed division modulus exx pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + call __DIVI32START - jp __MODU32START - + jp __MODU32START + #line 71 "divi32c.bas" #line 1 "swap32.asm" - + ; Exchanges current DE HL with the ; ones in the stack - + __SWAP32: pop bc ; Return address ex (sp), hl @@ -272,9 +272,9 @@ __SWAP32: inc sp push bc ret - + #line 72 "divi32c.bas" - + ZXBASIC_USER_DATA: _level: DEFB 01h diff --git a/tests/functional/divi8.asm b/tests/functional/divi8.asm index 47fbea1e8..5d99b6b6e 100644 --- a/tests/functional/divi8.asm +++ b/tests/functional/divi8.asm @@ -54,50 +54,50 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div8.asm" - + ; -------------------------------- -__DIVU8: ; 8 bit unsigned integer division +__DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A pop hl ; -------------------------------- ex (sp), hl ; CALLEE - + __DIVU8_FAST: ; Does A / H ld l, h ld h, a ; At this point do H / L - + ld b, 8 xor a ; A = 0, Carry Flag = 0 - + __DIV8LOOP: - sla h - rla - cp l + sla h + rla + cp l jr c, __DIV8NOSUB - sub l - inc h - -__DIV8NOSUB: + sub l + inc h + +__DIV8NOSUB: djnz __DIV8LOOP - + ld l, a ; save remainder - ld a, h ; - - ret ; a = Quotient, - - + ld a, h ; + + ret ; a = Quotient, + + ; -------------------------------- __DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A pop hl ; -------------------------------- ex (sp), hl - + __DIVI8_FAST: ld e, a ; store operands for later ld c, h - + or a ; negative? jp p, __DIV8A neg ; Make it positive - + __DIV8A: ex af, af' ld a, h @@ -105,45 +105,45 @@ __DIV8A: jp p, __DIV8B neg ld h, a ; make it positive - + __DIV8B: ex af, af' - + call __DIVU8_FAST - + ld a, c xor l ; bit 7 of A = 1 if result is negative - + ld a, h ; Quotient - ret p ; return if positive - + ret p ; return if positive + neg ret - - + + __MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) pop hl ex (sp), hl ; CALLEE - + __MODU8_FAST: ; __FASTCALL__ entry call __DIVU8_FAST ld a, l ; Remainder - + ret ; a = Modulus - - + + __MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) pop hl ex (sp), hl ; CALLEE - + __MODI8_FAST: ; __FASTCALL__ entry call __DIVI8_FAST ld a, l ; remainder - + ret ; a = Modulus - + #line 45 "divi8.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/divi8a.asm b/tests/functional/divi8a.asm index 612afbfa9..508914121 100644 --- a/tests/functional/divi8a.asm +++ b/tests/functional/divi8a.asm @@ -33,50 +33,50 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div8.asm" - + ; -------------------------------- -__DIVU8: ; 8 bit unsigned integer division +__DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A pop hl ; -------------------------------- ex (sp), hl ; CALLEE - + __DIVU8_FAST: ; Does A / H ld l, h ld h, a ; At this point do H / L - + ld b, 8 xor a ; A = 0, Carry Flag = 0 - + __DIV8LOOP: - sla h - rla - cp l + sla h + rla + cp l jr c, __DIV8NOSUB - sub l - inc h - -__DIV8NOSUB: + sub l + inc h + +__DIV8NOSUB: djnz __DIV8LOOP - + ld l, a ; save remainder - ld a, h ; - - ret ; a = Quotient, - - + ld a, h ; + + ret ; a = Quotient, + + ; -------------------------------- __DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A pop hl ; -------------------------------- ex (sp), hl - + __DIVI8_FAST: ld e, a ; store operands for later ld c, h - + or a ; negative? jp p, __DIV8A neg ; Make it positive - + __DIV8A: ex af, af' ld a, h @@ -84,45 +84,45 @@ __DIV8A: jp p, __DIV8B neg ld h, a ; make it positive - + __DIV8B: ex af, af' - + call __DIVU8_FAST - + ld a, c xor l ; bit 7 of A = 1 if result is negative - + ld a, h ; Quotient - ret p ; return if positive - + ret p ; return if positive + neg ret - - + + __MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) pop hl ex (sp), hl ; CALLEE - + __MODU8_FAST: ; __FASTCALL__ entry call __DIVU8_FAST ld a, l ; Remainder - + ret ; a = Modulus - - + + __MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) pop hl ex (sp), hl ; CALLEE - + __MODI8_FAST: ; __FASTCALL__ entry call __DIVI8_FAST ld a, l ; remainder - + ret ; a = Modulus - + #line 24 "divi8a.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/divi8b.asm b/tests/functional/divi8b.asm index 657fb85c6..48e4bf660 100644 --- a/tests/functional/divi8b.asm +++ b/tests/functional/divi8b.asm @@ -39,50 +39,50 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div8.asm" - + ; -------------------------------- -__DIVU8: ; 8 bit unsigned integer division +__DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A pop hl ; -------------------------------- ex (sp), hl ; CALLEE - + __DIVU8_FAST: ; Does A / H ld l, h ld h, a ; At this point do H / L - + ld b, 8 xor a ; A = 0, Carry Flag = 0 - + __DIV8LOOP: - sla h - rla - cp l + sla h + rla + cp l jr c, __DIV8NOSUB - sub l - inc h - -__DIV8NOSUB: + sub l + inc h + +__DIV8NOSUB: djnz __DIV8LOOP - + ld l, a ; save remainder - ld a, h ; - - ret ; a = Quotient, - - + ld a, h ; + + ret ; a = Quotient, + + ; -------------------------------- __DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A pop hl ; -------------------------------- ex (sp), hl - + __DIVI8_FAST: ld e, a ; store operands for later ld c, h - + or a ; negative? jp p, __DIV8A neg ; Make it positive - + __DIV8A: ex af, af' ld a, h @@ -90,45 +90,45 @@ __DIV8A: jp p, __DIV8B neg ld h, a ; make it positive - + __DIV8B: ex af, af' - + call __DIVU8_FAST - + ld a, c xor l ; bit 7 of A = 1 if result is negative - + ld a, h ; Quotient - ret p ; return if positive - + ret p ; return if positive + neg ret - - + + __MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) pop hl ex (sp), hl ; CALLEE - + __MODU8_FAST: ; __FASTCALL__ entry call __DIVU8_FAST ld a, l ; Remainder - + ret ; a = Modulus - - + + __MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) pop hl ex (sp), hl ; CALLEE - + __MODI8_FAST: ; __FASTCALL__ entry call __DIVI8_FAST ld a, l ; remainder - + ret ; a = Modulus - + #line 30 "divi8b.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/divu16.asm b/tests/functional/divu16.asm index 9465a7048..38807632a 100644 --- a/tests/functional/divu16.asm +++ b/tests/functional/divu16.asm @@ -55,17 +55,17 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div16.asm" - - ; 16 bit division and modulo functions + + ; 16 bit division and modulo functions ; for both signed and unsigned values - + #line 1 "neg16.asm" - + ; Negates HL value (16 bit) __ABS16: bit 7, h ret z - + __NEGHL: ld a, l ; HL = -HL cpl @@ -75,23 +75,23 @@ __NEGHL: ld h, a inc hl ret - + #line 5 "div16.asm" - + __DIVU16: ; 16 bit unsigned division ; HL = Dividend, Stack Top = Divisor - + ; -- OBSOLETE ; Now uses FASTCALL convention ; ex de, hl ; pop hl ; Return address ; ex (sp), hl ; CALLEE Convention - + __DIVU16_FAST: ld a, h ld c, l ld hl, 0 ld b, 16 - + __DIV16LOOP: sll c rla @@ -100,46 +100,46 @@ __DIV16LOOP: jr nc, __DIV16NOADD add hl,de dec c - + __DIV16NOADD: djnz __DIV16LOOP - + ex de, hl ld h, a ld l, c - + ret ; HL = quotient, DE = Mudulus - - - + + + __MODU16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVU16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - - + + __DIVI16: ; 16 bit signed division ; --- The following is OBSOLETE --- ; ex de, hl ; pop hl ; ex (sp), hl ; CALLEE Convention - + __DIVI16_FAST: ld a, d xor h ex af, af' ; BIT 7 of a contains result - + bit 7, d ; DE is negative? - jr z, __DIVI16A - + jr z, __DIVI16A + ld a, e ; DE = -DE cpl ld e, a @@ -147,35 +147,35 @@ __DIVI16_FAST: cpl ld d, a inc de - + __DIVI16A: bit 7, h ; HL is negative? call nz, __NEGHL - + __DIVI16B: call __DIVU16_FAST ex af, af' - - or a + + or a ret p ; return if positive jp __NEGHL - - + + __MODI16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVI16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - + #line 46 "divu16.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/divu16a.asm b/tests/functional/divu16a.asm index 23e1dee44..1e418a809 100644 --- a/tests/functional/divu16a.asm +++ b/tests/functional/divu16a.asm @@ -33,17 +33,17 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div16.asm" - - ; 16 bit division and modulo functions + + ; 16 bit division and modulo functions ; for both signed and unsigned values - + #line 1 "neg16.asm" - + ; Negates HL value (16 bit) __ABS16: bit 7, h ret z - + __NEGHL: ld a, l ; HL = -HL cpl @@ -53,23 +53,23 @@ __NEGHL: ld h, a inc hl ret - + #line 5 "div16.asm" - + __DIVU16: ; 16 bit unsigned division ; HL = Dividend, Stack Top = Divisor - + ; -- OBSOLETE ; Now uses FASTCALL convention ; ex de, hl ; pop hl ; Return address ; ex (sp), hl ; CALLEE Convention - + __DIVU16_FAST: ld a, h ld c, l ld hl, 0 ld b, 16 - + __DIV16LOOP: sll c rla @@ -78,46 +78,46 @@ __DIV16LOOP: jr nc, __DIV16NOADD add hl,de dec c - + __DIV16NOADD: djnz __DIV16LOOP - + ex de, hl ld h, a ld l, c - + ret ; HL = quotient, DE = Mudulus - - - + + + __MODU16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVU16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - - + + __DIVI16: ; 16 bit signed division ; --- The following is OBSOLETE --- ; ex de, hl ; pop hl ; ex (sp), hl ; CALLEE Convention - + __DIVI16_FAST: ld a, d xor h ex af, af' ; BIT 7 of a contains result - + bit 7, d ; DE is negative? - jr z, __DIVI16A - + jr z, __DIVI16A + ld a, e ; DE = -DE cpl ld e, a @@ -125,35 +125,35 @@ __DIVI16_FAST: cpl ld d, a inc de - + __DIVI16A: bit 7, h ; HL is negative? call nz, __NEGHL - + __DIVI16B: call __DIVU16_FAST ex af, af' - - or a + + or a ret p ; return if positive jp __NEGHL - - + + __MODI16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVI16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - + #line 24 "divu16a.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/divu16b.asm b/tests/functional/divu16b.asm index 4cfbf8bf6..fe63f4a4a 100644 --- a/tests/functional/divu16b.asm +++ b/tests/functional/divu16b.asm @@ -40,17 +40,17 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div16.asm" - - ; 16 bit division and modulo functions + + ; 16 bit division and modulo functions ; for both signed and unsigned values - + #line 1 "neg16.asm" - + ; Negates HL value (16 bit) __ABS16: bit 7, h ret z - + __NEGHL: ld a, l ; HL = -HL cpl @@ -60,23 +60,23 @@ __NEGHL: ld h, a inc hl ret - + #line 5 "div16.asm" - + __DIVU16: ; 16 bit unsigned division ; HL = Dividend, Stack Top = Divisor - + ; -- OBSOLETE ; Now uses FASTCALL convention ; ex de, hl ; pop hl ; Return address ; ex (sp), hl ; CALLEE Convention - + __DIVU16_FAST: ld a, h ld c, l ld hl, 0 ld b, 16 - + __DIV16LOOP: sll c rla @@ -85,46 +85,46 @@ __DIV16LOOP: jr nc, __DIV16NOADD add hl,de dec c - + __DIV16NOADD: djnz __DIV16LOOP - + ex de, hl ld h, a ld l, c - + ret ; HL = quotient, DE = Mudulus - - - + + + __MODU16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVU16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - - + + __DIVI16: ; 16 bit signed division ; --- The following is OBSOLETE --- ; ex de, hl ; pop hl ; ex (sp), hl ; CALLEE Convention - + __DIVI16_FAST: ld a, d xor h ex af, af' ; BIT 7 of a contains result - + bit 7, d ; DE is negative? - jr z, __DIVI16A - + jr z, __DIVI16A + ld a, e ; DE = -DE cpl ld e, a @@ -132,35 +132,35 @@ __DIVI16_FAST: cpl ld d, a inc de - + __DIVI16A: bit 7, h ; HL is negative? call nz, __NEGHL - + __DIVI16B: call __DIVU16_FAST ex af, af' - - or a + + or a ret p ; return if positive jp __NEGHL - - + + __MODI16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVI16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - + #line 31 "divu16b.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/divu32c.asm b/tests/functional/divu32c.asm index e02ea30ea..18063a710 100644 --- a/tests/functional/divu32c.asm +++ b/tests/functional/divu32c.asm @@ -80,41 +80,41 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div32.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "div32.asm" - + ; --------------------------------------------------------- __DIVU32: ; 32 bit unsigned division ; DEHL = Dividend, Stack Top = Divisor @@ -126,7 +126,7 @@ __DIVU32: ; 32 bit unsigned division pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + __DIVU32START: ; Performs D'E'H'L' / HLDE ; Now switch to DIVIDEND = B'C'BC / DIVISOR = D'E'DE (A / B) push de ; push Lowpart(Q) @@ -142,9 +142,9 @@ __DIVU32START: ; Performs D'E'H'L' / HLDE exx pop bc ; Pop HightPart(B) => B = B'C'BC exx - + ld a, 32 ; Loop count - + __DIV32LOOP: sll c ; B'C'BC << 1 ; Output most left bit to carry rl b @@ -152,29 +152,29 @@ __DIV32LOOP: rl c rl b exx - + adc hl, hl exx adc hl, hl exx - + sbc hl,de exx sbc hl,de exx jp nc, __DIV32NOADD ; use JP inside a loop for being faster - + add hl, de exx adc hl, de exx dec bc - + __DIV32NOADD: dec a jp nz, __DIV32LOOP ; use JP inside a loop for being faster ; At this point, quotient is stored in B'C'BC and the reminder in H'L'HL - + push hl exx pop de @@ -184,34 +184,34 @@ __DIV32NOADD: pop de ; DE = B'C' ld h, b ld l, c ; DEHL = quotient D'E'H'L' = Modulus - + ret ; DEHL = quotient, D'E'H'L' = Modulus - - - + + + __MODU32: ; 32 bit modulus for 32bit unsigned division ; DEHL = Dividend, Stack Top = Divisor (DE, HL) - + exx pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + call __DIVU32START ; At return, modulus is at D'E'H'L' - + __MODU32START: - + exx push de push hl - - exx + + exx pop hl pop de - + ret - - + + __DIVI32: ; 32 bit signed division ; DEHL = Dividend, Stack Top = Divisor ; A = Dividend, B = Divisor => A / B @@ -219,47 +219,47 @@ __DIVI32: ; 32 bit signed division pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + __DIVI32START: exx ld a, d ; Save sign ex af, af' bit 7, d ; Negative? call nz, __NEG32 ; Negates DEHL - + exx ; Now works with H'L'D'E' ex af, af' xor h ex af, af' ; Stores sign of the result for later - + bit 7, h ; Negative? ex de, hl ; HLDE = DEHL call nz, __NEG32 - ex de, hl - + ex de, hl + call __DIVU32START ex af, af' ; Recovers sign and 128 ; positive? ret z - + jp __NEG32 ; Negates DEHL and returns from there - - + + __MODI32: ; 32bits signed division modulus exx pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + call __DIVI32START - jp __MODU32START - + jp __MODU32START + #line 71 "divu32c.bas" #line 1 "swap32.asm" - + ; Exchanges current DE HL with the ; ones in the stack - + __SWAP32: pop bc ; Return address ex (sp), hl @@ -272,9 +272,9 @@ __SWAP32: inc sp push bc ret - + #line 72 "divu32c.bas" - + ZXBASIC_USER_DATA: _level: DEFB 01h diff --git a/tests/functional/divu8.asm b/tests/functional/divu8.asm index 1a7dad4fb..bd523e67d 100644 --- a/tests/functional/divu8.asm +++ b/tests/functional/divu8.asm @@ -54,50 +54,50 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div8.asm" - + ; -------------------------------- -__DIVU8: ; 8 bit unsigned integer division +__DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A pop hl ; -------------------------------- ex (sp), hl ; CALLEE - + __DIVU8_FAST: ; Does A / H ld l, h ld h, a ; At this point do H / L - + ld b, 8 xor a ; A = 0, Carry Flag = 0 - + __DIV8LOOP: - sla h - rla - cp l + sla h + rla + cp l jr c, __DIV8NOSUB - sub l - inc h - -__DIV8NOSUB: + sub l + inc h + +__DIV8NOSUB: djnz __DIV8LOOP - + ld l, a ; save remainder - ld a, h ; - - ret ; a = Quotient, - - + ld a, h ; + + ret ; a = Quotient, + + ; -------------------------------- __DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A pop hl ; -------------------------------- ex (sp), hl - + __DIVI8_FAST: ld e, a ; store operands for later ld c, h - + or a ; negative? jp p, __DIV8A neg ; Make it positive - + __DIV8A: ex af, af' ld a, h @@ -105,45 +105,45 @@ __DIV8A: jp p, __DIV8B neg ld h, a ; make it positive - + __DIV8B: ex af, af' - + call __DIVU8_FAST - + ld a, c xor l ; bit 7 of A = 1 if result is negative - + ld a, h ; Quotient - ret p ; return if positive - + ret p ; return if positive + neg ret - - + + __MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) pop hl ex (sp), hl ; CALLEE - + __MODU8_FAST: ; __FASTCALL__ entry call __DIVU8_FAST ld a, l ; Remainder - + ret ; a = Modulus - - + + __MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) pop hl ex (sp), hl ; CALLEE - + __MODI8_FAST: ; __FASTCALL__ entry call __DIVI8_FAST ld a, l ; remainder - + ret ; a = Modulus - + #line 45 "divu8.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/divu8a.asm b/tests/functional/divu8a.asm index 0229d3f00..c81ed5912 100644 --- a/tests/functional/divu8a.asm +++ b/tests/functional/divu8a.asm @@ -33,50 +33,50 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div8.asm" - + ; -------------------------------- -__DIVU8: ; 8 bit unsigned integer division +__DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A pop hl ; -------------------------------- ex (sp), hl ; CALLEE - + __DIVU8_FAST: ; Does A / H ld l, h ld h, a ; At this point do H / L - + ld b, 8 xor a ; A = 0, Carry Flag = 0 - + __DIV8LOOP: - sla h - rla - cp l + sla h + rla + cp l jr c, __DIV8NOSUB - sub l - inc h - -__DIV8NOSUB: + sub l + inc h + +__DIV8NOSUB: djnz __DIV8LOOP - + ld l, a ; save remainder - ld a, h ; - - ret ; a = Quotient, - - + ld a, h ; + + ret ; a = Quotient, + + ; -------------------------------- __DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A pop hl ; -------------------------------- ex (sp), hl - + __DIVI8_FAST: ld e, a ; store operands for later ld c, h - + or a ; negative? jp p, __DIV8A neg ; Make it positive - + __DIV8A: ex af, af' ld a, h @@ -84,45 +84,45 @@ __DIV8A: jp p, __DIV8B neg ld h, a ; make it positive - + __DIV8B: ex af, af' - + call __DIVU8_FAST - + ld a, c xor l ; bit 7 of A = 1 if result is negative - + ld a, h ; Quotient - ret p ; return if positive - + ret p ; return if positive + neg ret - - + + __MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) pop hl ex (sp), hl ; CALLEE - + __MODU8_FAST: ; __FASTCALL__ entry call __DIVU8_FAST ld a, l ; Remainder - + ret ; a = Modulus - - + + __MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) pop hl ex (sp), hl ; CALLEE - + __MODI8_FAST: ; __FASTCALL__ entry call __DIVI8_FAST ld a, l ; remainder - + ret ; a = Modulus - + #line 24 "divu8a.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/divu8b.asm b/tests/functional/divu8b.asm index a7a965d01..f98ec2063 100644 --- a/tests/functional/divu8b.asm +++ b/tests/functional/divu8b.asm @@ -39,50 +39,50 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div8.asm" - + ; -------------------------------- -__DIVU8: ; 8 bit unsigned integer division +__DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A pop hl ; -------------------------------- ex (sp), hl ; CALLEE - + __DIVU8_FAST: ; Does A / H ld l, h ld h, a ; At this point do H / L - + ld b, 8 xor a ; A = 0, Carry Flag = 0 - + __DIV8LOOP: - sla h - rla - cp l + sla h + rla + cp l jr c, __DIV8NOSUB - sub l - inc h - -__DIV8NOSUB: + sub l + inc h + +__DIV8NOSUB: djnz __DIV8LOOP - + ld l, a ; save remainder - ld a, h ; - - ret ; a = Quotient, - - + ld a, h ; + + ret ; a = Quotient, + + ; -------------------------------- __DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A pop hl ; -------------------------------- ex (sp), hl - + __DIVI8_FAST: ld e, a ; store operands for later ld c, h - + or a ; negative? jp p, __DIV8A neg ; Make it positive - + __DIV8A: ex af, af' ld a, h @@ -90,45 +90,45 @@ __DIV8A: jp p, __DIV8B neg ld h, a ; make it positive - + __DIV8B: ex af, af' - + call __DIVU8_FAST - + ld a, c xor l ; bit 7 of A = 1 if result is negative - + ld a, h ; Quotient - ret p ; return if positive - + ret p ; return if positive + neg ret - - + + __MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) pop hl ex (sp), hl ; CALLEE - + __MODU8_FAST: ; __FASTCALL__ entry call __DIVU8_FAST ld a, l ; Remainder - + ret ; a = Modulus - - + + __MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) pop hl ex (sp), hl ; CALLEE - + __MODI8_FAST: ; __FASTCALL__ entry call __DIVI8_FAST ld a, l ; remainder - + ret ; a = Modulus - + #line 30 "divu8b.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/dollar.asm b/tests/functional/dollar.asm index 18b63bae6..bceba2626 100644 --- a/tests/functional/dollar.asm +++ b/tests/functional/dollar.asm @@ -29,7 +29,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/doloop.asm b/tests/functional/doloop.asm index df3d8d289..98bf9bbc9 100644 --- a/tests/functional/doloop.asm +++ b/tests/functional/doloop.asm @@ -49,7 +49,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/doloop1.asm b/tests/functional/doloop1.asm index 93885068f..b7f6f3e08 100644 --- a/tests/functional/doloop1.asm +++ b/tests/functional/doloop1.asm @@ -29,7 +29,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/doloop2.asm b/tests/functional/doloop2.asm index f6fff4bc5..632da5bec 100644 --- a/tests/functional/doloop2.asm +++ b/tests/functional/doloop2.asm @@ -45,7 +45,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/doloop3.asm b/tests/functional/doloop3.asm index a6a75e09b..4473b0580 100644 --- a/tests/functional/doloop3.asm +++ b/tests/functional/doloop3.asm @@ -46,7 +46,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/dountil1.asm b/tests/functional/dountil1.asm index ef2592285..20fc6c5c2 100644 --- a/tests/functional/dountil1.asm +++ b/tests/functional/dountil1.asm @@ -30,7 +30,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/dowhile1.asm b/tests/functional/dowhile1.asm index ef2592285..20fc6c5c2 100644 --- a/tests/functional/dowhile1.asm +++ b/tests/functional/dowhile1.asm @@ -30,7 +30,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/draw.asm b/tests/functional/draw.asm index aa89de316..f489f59fa 100644 --- a/tests/functional/draw.asm +++ b/tests/functional/draw.asm @@ -55,29 +55,29 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "draw.asm" - + ; DRAW using bresenhams algorithm and screen positioning ; Copyleft (k) 2010 by J. Rodriguez (a.k.a. Boriel) http://www.boriel.com ; vim:ts=4:et:sw=4: - + ; Y parameter in A ; X parameter in high byte on top of the stack - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -85,12 +85,12 @@ __CALL_BACK__: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -98,7 +98,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -106,13 +106,13 @@ __STOP: ret #line 9 "draw.asm" #line 1 "in_screen.asm" - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -120,76 +120,76 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 2 "in_screen.asm" - - + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 10 "draw.asm" - + #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -202,188 +202,188 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 12 "draw.asm" - + #line 1 "PixelDown.asm" - - ; - ; PixelDown - ; Alvin Albrecht 2002 - ; - - ; Pixel Down - ; - ; Adjusts screen address HL to move one pixel down in the display. - ; (0,0) is located at the top left corner of the screen. - ; -; enter: HL = valid screen address -; exit : Carry = moved off screen - ; Carry'= moved off current cell (needs ATTR update) - ; HL = moves one pixel down -; used : AF, HL - -SP.PixelDown: - inc h - ld a,h - and $07 - ret nz - ex af, af' ; Sets carry on F' - scf ; which flags ATTR must be updated - ex af, af' - ld a,h - sub $08 - ld h,a - ld a,l - add a,$20 - ld l,a - ret nc - ld a,h - add a,$08 - ld h,a - ;IF DISP_HIRES - ; and $18 - ; cp $18 - ;ELSE - cp $58 - ;ENDIF - ccf - ret + + ; + ; PixelDown + ; Alvin Albrecht 2002 + ; + + ; Pixel Down + ; + ; Adjusts screen address HL to move one pixel down in the display. + ; (0,0) is located at the top left corner of the screen. + ; +; enter: HL = valid screen address +; exit : Carry = moved off screen + ; Carry'= moved off current cell (needs ATTR update) + ; HL = moves one pixel down +; used : AF, HL + +SP.PixelDown: + inc h + ld a,h + and $07 + ret nz + ex af, af' ; Sets carry on F' + scf ; which flags ATTR must be updated + ex af, af' + ld a,h + sub $08 + ld h,a + ld a,l + add a,$20 + ld l,a + ret nc + ld a,h + add a,$08 + ld h,a + ;IF DISP_HIRES + ; and $18 + ; cp $18 + ;ELSE + cp $58 + ;ENDIF + ccf + ret #line 14 "draw.asm" #line 1 "PixelUp.asm" - - ; - ; PixelUp - ; Alvin Albrecht 2002 - ; - - ; Pixel Up - ; - ; Adjusts screen address HL to move one pixel up in the display. - ; (0,0) is located at the top left corner of the screen. - ; -; enter: HL = valid screen address -; exit : Carry = moved off screen - ; HL = moves one pixel up -; used : AF, HL - -SP.PixelUp: - ld a,h - dec h - and $07 - ret nz - ex af, af' - scf - ex af, af' - ld a,$08 - add a,h - ld h,a - ld a,l - sub $20 - ld l,a - ret nc - ld a,h - sub $08 - ld h,a - ;IF DISP_HIRES - ; and $18 - ; cp $18 - ; ccf - ;ELSE - cp $40 - ;ENDIF - ret + + ; + ; PixelUp + ; Alvin Albrecht 2002 + ; + + ; Pixel Up + ; + ; Adjusts screen address HL to move one pixel up in the display. + ; (0,0) is located at the top left corner of the screen. + ; +; enter: HL = valid screen address +; exit : Carry = moved off screen + ; HL = moves one pixel up +; used : AF, HL + +SP.PixelUp: + ld a,h + dec h + and $07 + ret nz + ex af, af' + scf + ex af, af' + ld a,$08 + add a,h + ld h,a + ld a,l + sub $20 + ld l,a + ret nc + ld a,h + sub $08 + ld h,a + ;IF DISP_HIRES + ; and $18 + ; cp $18 + ; ccf + ;ELSE + cp $40 + ;ENDIF + ret #line 15 "draw.asm" #line 1 "PixelLeft.asm" - - ; - ; PixelLeft - ; Jose Rodriguez 2012 - ; - - ; PixelLeft - ; - ; Adjusts screen address HL and Pixel bit A to move one pixel to the left - ; on the display. Start of line set Carry (Out of Screen) - ; -; enter: HL = valid screen address - ; A = Bit Set -; exit : Carry = moved off screen - ; Carry' Set if moved off current ATTR CELL - ; HL = moves one character left, if needed - ; A = Bit Set with new pixel pos. -; used : AF, HL - - -SP.PixelLeft: - rlca ; Sets new pixel bit 1 to the right - ret nc - ex af, af' ; Signal in C' we've moved off current ATTR cell - ld a,l - dec a - ld l,a - cp 32 ; Carry if in screen - ccf - ld a, 1 - ret - + + ; + ; PixelLeft + ; Jose Rodriguez 2012 + ; + + ; PixelLeft + ; + ; Adjusts screen address HL and Pixel bit A to move one pixel to the left + ; on the display. Start of line set Carry (Out of Screen) + ; +; enter: HL = valid screen address + ; A = Bit Set +; exit : Carry = moved off screen + ; Carry' Set if moved off current ATTR CELL + ; HL = moves one character left, if needed + ; A = Bit Set with new pixel pos. +; used : AF, HL + + +SP.PixelLeft: + rlca ; Sets new pixel bit 1 to the right + ret nc + ex af, af' ; Signal in C' we've moved off current ATTR cell + ld a,l + dec a + ld l,a + cp 32 ; Carry if in screen + ccf + ld a, 1 + ret + #line 16 "draw.asm" #line 1 "PixelRight.asm" - - ; - ; PixelRight - ; Jose Rodriguez 2012 - ; - - - ; PixelRight - ; - ; Adjusts screen address HL and Pixel bit A to move one pixel to the left - ; on the display. Start of line set Carry (Out of Screen) - ; -; enter: HL = valid screen address - ; A = Bit Set -; exit : Carry = moved off screen - ; Carry' Set if moved off current ATTR CELL - ; HL = moves one character left, if needed - ; A = Bit Set with new pixel pos. -; used : AF, HL - - -SP.PixelRight: - rrca ; Sets new pixel bit 1 to the right - ret nc - ex af, af' ; Signal in C' we've moved off current ATTR cell - ld a, l - inc a - ld l, a - cp 32 ; Carry if IN screen - ccf - ld a, 80h - ret - + + ; + ; PixelRight + ; Jose Rodriguez 2012 + ; + + + ; PixelRight + ; + ; Adjusts screen address HL and Pixel bit A to move one pixel to the left + ; on the display. Start of line set Carry (Out of Screen) + ; +; enter: HL = valid screen address + ; A = Bit Set +; exit : Carry = moved off screen + ; Carry' Set if moved off current ATTR CELL + ; HL = moves one character left, if needed + ; A = Bit Set with new pixel pos. +; used : AF, HL + + +SP.PixelRight: + rrca ; Sets new pixel bit 1 to the right + ret nc + ex af, af' ; Signal in C' we've moved off current ATTR cell + ld a, l + inc a + ld l, a + cp 32 ; Carry if IN screen + ccf + ld a, 80h + ret + #line 17 "draw.asm" - + ;; DRAW PROCEDURE - PROC - + PROC + LOCAL __DRAW1 LOCAL __DRAW2 LOCAL __DRAW3 @@ -395,22 +395,22 @@ SP.PixelRight: LOCAL __INCX, __INCY, __DECX, __DECY LOCAL P_FLAG P_FLAG EQU 23697 - + __DRAW_ERROR: jp __OUT_OF_SCREEN_ERR - + DRAW: ;; ENTRY POINT - + LOCAL PIXEL_ADDR LOCAL COORDS LOCAL __DRAW_SETUP1, __DRAW_START, __PLOTOVER, __PLOTINVERSE - + ex de, hl ; DE = Y OFFSET pop hl ; return addr ex (sp), hl ; CALLEE => HL = X OFFSET ld bc, (COORDS) - + ld a, c add a, l ld l, a @@ -418,26 +418,26 @@ DRAW: adc a, 0 ; HL = HL + C ld h, a jr nz, __DRAW_ERROR ; if a <> 0 => Out of Screen - + ld a, b add a, e - ld e, a + ld e, a ld a, d adc a, 0 ; DE = DE + B ld d, a jr nz, __DRAW_ERROR ; if a <> 0 => Out of Screen - + ld a, 191 sub e jr c, __DRAW_ERROR ; Out of screen - + ld h, e ; now H,L = y2, x2 - + __DRAW: ; __FASTCALL__ Entry. Plots from (COORDS) to coord H, L push hl ex de, hl ; D,E = y2, x2; - + ld a, (P_FLAG) ld c, a bit 2, a ; Test for INVERSE1 @@ -446,7 +446,7 @@ __DRAW: ld (__PLOTINVERSE), a ld a, 0A6h ; and (hl) jp __DRAW_START - + __DRAW_SETUP1: xor a ; nop ld (__PLOTINVERSE), a @@ -454,7 +454,7 @@ __DRAW_SETUP1: bit 0, c ; Test for OVER jr z, __DRAW_START ld a, 0AEh ; xor (hl) - + __DRAW_START: ld (__PLOTOVER), a ; "Pokes" last operation exx @@ -464,7 +464,7 @@ __DRAW_START: LOCAL __PIXEL_ADDR __PIXEL_ADDR EQU 22ACh call __PIXEL_ADDR - + ;; Now gets pixel mask in A register ld b, a inc b @@ -474,7 +474,7 @@ __DRAW_START: __PIXEL_MASK: rra djnz __PIXEL_MASK - + ld b, d ; Restores B' from D' pop de ; D'E' = y2, x2 exx ; At this point: D'E' = y2,x2 coords @@ -482,147 +482,147 @@ __PIXEL_MASK: ex af, af' ; Saves A reg for later ; A' = Pixel mask ; H'L' = Screen Address of pixel - + ld bc, (COORDS) ; B,C = y1, x1 - - ld a, e + + ld a, e sub c ; dx = X2 - X1 ld c, a ; Saves dx in c - + ld a, 0Ch ; INC C opcode ld hl, __INCX ; xi = 1 jr nc, __DRAW1 - + ld a, c neg ; dx = X1 - X2 ld c, a ld a, 0Dh ; DEC C opcode ld hl, __DECX ; xi = -1 - + __DRAW1: ld (DX1), a ld (DX1 + 2), hl ; Updates DX1 call address ld (DX2), a ld (DX2 + 2), hl ; Updates DX2 call address - + ld a, d sub b ; dy = Y2 - Y1 ld b, a ; Saves dy in b - + ld a, 4 ; INC B opcode ld hl, __INCY ; y1 = 1 jr nc, __DRAW2 - + ld a, b neg ld b, a ; dy = Y2 - Y1 ld a, 5 ; DEC B opcode ld hl, __DECY ; y1 = -1 - + __DRAW2: ld (DY1), a ld (DY1 + 2), hl ; Updates DX1 call address ld (DY2), a ld (DY2 + 2), hl ; Updates DX2 call address - + ld a, b sub c ; dy - dx jr c, __DRAW_DX_GT_DY ; DX > DY - + ; At this point DY >= DX ; -------------------------- ; HL = error = dY / 2 ld h, 0 ld l, b srl l - + ; DE = -dX xor a sub c ld e, a sbc a, a ld d, a - + ; BC = DY ld c, b ld b, h - + exx scf ; Sets Carry to signal update ATTR ex af, af' ; Brings back pixel mask ld e, a ; Saves it in free E register jp __DRAW4_LOOP - + __DRAW3: ; While c != e => while y != y2 exx add hl, de ; error -= dX bit 7, h ; exx ; recover coordinates - jr z, __DRAW4 ; if error < 0 - + jr z, __DRAW4 ; if error < 0 + exx - add hl, bc ; error += dY + add hl, bc ; error += dY exx - + ld a, e DX1: ; x += xi inc c call __INCX ; This address will be dynamically updated ld e, a - + __DRAW4: - + DY1: ; y += yi inc b call __INCY ; This address will be dyncamically updated ld a, e ; Restores A reg. call __FASTPLOT - + __DRAW4_LOOP: ld a, b cp d jp nz, __DRAW3 ld (COORDS), bc - ret - + ret + __DRAW_DX_GT_DY: ; DX > DY ; -------------------------- ; HL = error = dX / 2 ld h, 0 - ld l, c + ld l, c srl l ; HL = error = DX / 2 - + ; DE = -dY xor a sub b ld e, a sbc a, a ld d, a - + ; BC = dX ld b, h - + exx ld d, e scf ; Sets Carry to signal update ATTR ex af, af' ; Brings back pixel mask ld e, a ; Saves it in free E register jp __DRAW6_LOOP - + __DRAW5: ; While loop exx add hl, de ; error -= dY bit 7, h ; if (error < 0) exx ; Restore coords - jr z, __DRAW6 ; + jr z, __DRAW6 ; exx add hl, bc ; error += dX - exx - + exx + DY2: ; y += yi inc b call __INCY ; This address will be dynamically updated - + __DRAW6: ld a, e DX2: ; x += xi @@ -630,40 +630,40 @@ DX2: ; x += xi call __INCX ; This address will be dynamically updated ld e, a call __FASTPLOT - + __DRAW6_LOOP: ld a, c ; Current X coord cp d jp nz, __DRAW5 ld (COORDS), bc ret - - PIXEL_ADDR EQU 22ACh + + PIXEL_ADDR EQU 22ACh COORDS EQU 5C7Dh - + __DRAW_END: exx ret - + ;; Given a A mask and an HL screen position ;; return the next left position ;; Also updates BC coords __DECX EQU SP.PixelLeft - + ;; Like the above, but to the RIGHT ;; Also updates BC coords __INCX EQU SP.PixelRight - + ;; Given an HL screen position, calculates ;; the above position ;; Also updates BC coords __INCY EQU SP.PixelUp - + ;; Given an HL screen position, calculates ;; the above position ;; Also updates BC coords __DECY EQU SP.PixelDown - + ;; Puts the A register MASK in (HL) __FASTPLOT: __PLOTINVERSE: @@ -671,12 +671,12 @@ __PLOTINVERSE: __PLOTOVER: or (hl) ; Replace with XOR (hl) if OVER 1 AND INVERSE 0 ; Replace with AND (hl) if INVERSE 1 - + ld (hl), a ex af, af' ; Recovers flag. If Carry set => update ATTR ld a, e ; Recovers A reg ret nc - + push hl push de ;; gets ATTR position with offset given in SCREEN_ADDR @@ -689,71 +689,71 @@ __PLOTOVER: ld h, a ld de, (SCREEN_ADDR) add hl, de ;; Final screen addr - + LOCAL PO_ATTR_2 PO_ATTR_2 EQU 0BE4h ; Another entry to PO_ATTR call PO_ATTR_2 ; This will update attr accordingly. Beware, uses IY - + pop de pop hl - - LOCAL __FASTPLOTEND -__FASTPLOTEND: + + LOCAL __FASTPLOTEND +__FASTPLOTEND: or a ; Resets carry flag ex af, af' ; Recovers A reg ld a, e ret - + ENDP - + #line 46 "draw.bas" #line 1 "ftou32reg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "ftou32reg.asm" - + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) PROC - + LOCAL __IS_FLOAT - + or a - jr nz, __IS_FLOAT + jr nz, __IS_FLOAT ; Here if it is a ZX ROM Integer - + ld h, c ld l, d ld a, e ; Takes sign: FF = -, 0 = + @@ -761,64 +761,64 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS inc a jp z, __NEG32 ; Negates if negative ret - + __IS_FLOAT: ; Jumps here if it is a true floating point number - ld h, e + ld h, e push hl ; Stores it for later (Contains Sign in H) - + push de push bc - + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + ;ld a, c ; Get exponent sub 128 ; Exponent -= 128 jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 - + __FTOU32REG_LOOP: exx ; Shift C'B' E'D' << 1, output bit stays in Carry sla d rl e rl b rl c - + exx ; Shift DEHL << 1, inserting the carry on the right rl l rl h rl e rl d - + djnz __FTOU32REG_LOOP - + __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative jp m, __NEG32 ; Negates DEHL - + ret - + ENDP - - + + __FTOU8: ; Converts float in C ED LH to Unsigned byte in A call __FTOU32REG ld a, l ret - + #line 47 "draw.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00, 00 diff --git a/tests/functional/draw3.asm b/tests/functional/draw3.asm index cc76b547e..e10f28473 100644 --- a/tests/functional/draw3.asm +++ b/tests/functional/draw3.asm @@ -85,31 +85,31 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "draw3.asm" - + ; ----------------------------------------------------------- -; vim: et:ts=4:sw=4:ruler: +; vim: et:ts=4:sw=4:ruler: ; ; DRAW an arc using ZX ROM algorithm. ; DRAW x, y, r => r = Arc in radians - + ; r parameter in A ED BC register ; X, and Y parameter in high byte on top of the stack - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -117,12 +117,12 @@ __CALL_BACK__: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -130,7 +130,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -138,22 +138,22 @@ __STOP: ret #line 11 "draw3.asm" #line 1 "plot.asm" - + ; MIXED __FASTCAL__ / __CALLE__ PLOT Function ; Plots a point into the screen calling the ZX ROM PLOT routine - + ; Y in A (accumulator) ; X in top of the stack - - + + #line 1 "in_screen.asm" - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -161,75 +161,75 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 2 "in_screen.asm" - - + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 9 "plot.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -242,48 +242,48 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 10 "plot.asm" - + PLOT: PROC - + LOCAL PLOT_SUB LOCAL PIXEL_ADDR LOCAL COORDS LOCAL __PLOT_ERR LOCAL P_FLAG LOCAL __PLOT_OVER1 - + P_FLAG EQU 23697 - + pop hl ex (sp), hl ; Callee - + ld b, a - ld c, h - + ld c, h + ld a, 191 cp b jr c, __PLOT_ERR ; jr is faster here (#1) - + __PLOT: ; __FASTCALL__ entry (b, c) = pixel coords (y, x) ld (COORDS), bc ; Saves current point ld a, 191 ; Max y coord @@ -291,7 +291,7 @@ __PLOT: ; __FASTCALL__ entry (b, c) = pixel coords (y, x) res 6, h ; Starts from 0 ld bc, (SCREEN_ADDR) add hl, bc ; Now current offset - + ld b, a inc b ld a, 0FEh @@ -299,7 +299,7 @@ __PLOT: ; __FASTCALL__ entry (b, c) = pixel coords (y, x) __PLOT_LOOP: rrca djnz __PLOT_LOOP - + ld b, a ld a, (P_FLAG) ld c, a @@ -307,18 +307,18 @@ __PLOT_LOOP: bit 0, c ; is it OVER 1 jr nz, __PLOT_OVER1 and b - + __PLOT_OVER1: bit 2, c ; is it inverse 1 jr nz, __PLOT_END - + xor b cpl - + LOCAL __PLOT_END __PLOT_END: ld (hl), a - + ;; gets ATTR position with offset given in SCREEN_ADDR ld a, h rrca @@ -329,52 +329,52 @@ __PLOT_END: ld h, a ld de, (SCREEN_ADDR) add hl, de ;; Final screen addr - + LOCAL PO_ATTR_2 PO_ATTR_2 EQU 0BE4h ; Another entry to PO_ATTR jp PO_ATTR_2 ; This will update attr accordingly. Beware, uses IY - + __PLOT_ERR: jp __OUT_OF_SCREEN_ERR ; Spent 3 bytes, but saves 3 T-States at (#1) - + PLOT_SUB EQU 22ECh - PIXEL_ADDR EQU 22ACh + PIXEL_ADDR EQU 22ACh COORDS EQU 5C7Dh ENDP #line 12 "draw3.asm" #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -391,181 +391,181 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK jp __FPSTACK_PUSH #line 13 "draw3.asm" #line 1 "draw.asm" - + ; DRAW using bresenhams algorithm and screen positioning ; Copyleft (k) 2010 by J. Rodriguez (a.k.a. Boriel) http://www.boriel.com ; vim:ts=4:et:sw=4: - + ; Y parameter in A ; X parameter in high byte on top of the stack - - - - - - + + + + + + #line 1 "PixelDown.asm" - - ; - ; PixelDown - ; Alvin Albrecht 2002 - ; - - ; Pixel Down - ; - ; Adjusts screen address HL to move one pixel down in the display. - ; (0,0) is located at the top left corner of the screen. - ; -; enter: HL = valid screen address -; exit : Carry = moved off screen - ; Carry'= moved off current cell (needs ATTR update) - ; HL = moves one pixel down -; used : AF, HL - -SP.PixelDown: - inc h - ld a,h - and $07 - ret nz - ex af, af' ; Sets carry on F' - scf ; which flags ATTR must be updated - ex af, af' - ld a,h - sub $08 - ld h,a - ld a,l - add a,$20 - ld l,a - ret nc - ld a,h - add a,$08 - ld h,a - ;IF DISP_HIRES - ; and $18 - ; cp $18 - ;ELSE - cp $58 - ;ENDIF - ccf - ret + + ; + ; PixelDown + ; Alvin Albrecht 2002 + ; + + ; Pixel Down + ; + ; Adjusts screen address HL to move one pixel down in the display. + ; (0,0) is located at the top left corner of the screen. + ; +; enter: HL = valid screen address +; exit : Carry = moved off screen + ; Carry'= moved off current cell (needs ATTR update) + ; HL = moves one pixel down +; used : AF, HL + +SP.PixelDown: + inc h + ld a,h + and $07 + ret nz + ex af, af' ; Sets carry on F' + scf ; which flags ATTR must be updated + ex af, af' + ld a,h + sub $08 + ld h,a + ld a,l + add a,$20 + ld l,a + ret nc + ld a,h + add a,$08 + ld h,a + ;IF DISP_HIRES + ; and $18 + ; cp $18 + ;ELSE + cp $58 + ;ENDIF + ccf + ret #line 14 "draw.asm" #line 1 "PixelUp.asm" - - ; - ; PixelUp - ; Alvin Albrecht 2002 - ; - - ; Pixel Up - ; - ; Adjusts screen address HL to move one pixel up in the display. - ; (0,0) is located at the top left corner of the screen. - ; -; enter: HL = valid screen address -; exit : Carry = moved off screen - ; HL = moves one pixel up -; used : AF, HL - -SP.PixelUp: - ld a,h - dec h - and $07 - ret nz - ex af, af' - scf - ex af, af' - ld a,$08 - add a,h - ld h,a - ld a,l - sub $20 - ld l,a - ret nc - ld a,h - sub $08 - ld h,a - ;IF DISP_HIRES - ; and $18 - ; cp $18 - ; ccf - ;ELSE - cp $40 - ;ENDIF - ret + + ; + ; PixelUp + ; Alvin Albrecht 2002 + ; + + ; Pixel Up + ; + ; Adjusts screen address HL to move one pixel up in the display. + ; (0,0) is located at the top left corner of the screen. + ; +; enter: HL = valid screen address +; exit : Carry = moved off screen + ; HL = moves one pixel up +; used : AF, HL + +SP.PixelUp: + ld a,h + dec h + and $07 + ret nz + ex af, af' + scf + ex af, af' + ld a,$08 + add a,h + ld h,a + ld a,l + sub $20 + ld l,a + ret nc + ld a,h + sub $08 + ld h,a + ;IF DISP_HIRES + ; and $18 + ; cp $18 + ; ccf + ;ELSE + cp $40 + ;ENDIF + ret #line 15 "draw.asm" #line 1 "PixelLeft.asm" - - ; - ; PixelLeft - ; Jose Rodriguez 2012 - ; - - ; PixelLeft - ; - ; Adjusts screen address HL and Pixel bit A to move one pixel to the left - ; on the display. Start of line set Carry (Out of Screen) - ; -; enter: HL = valid screen address - ; A = Bit Set -; exit : Carry = moved off screen - ; Carry' Set if moved off current ATTR CELL - ; HL = moves one character left, if needed - ; A = Bit Set with new pixel pos. -; used : AF, HL - - -SP.PixelLeft: - rlca ; Sets new pixel bit 1 to the right - ret nc - ex af, af' ; Signal in C' we've moved off current ATTR cell - ld a,l - dec a - ld l,a - cp 32 ; Carry if in screen - ccf - ld a, 1 - ret - + + ; + ; PixelLeft + ; Jose Rodriguez 2012 + ; + + ; PixelLeft + ; + ; Adjusts screen address HL and Pixel bit A to move one pixel to the left + ; on the display. Start of line set Carry (Out of Screen) + ; +; enter: HL = valid screen address + ; A = Bit Set +; exit : Carry = moved off screen + ; Carry' Set if moved off current ATTR CELL + ; HL = moves one character left, if needed + ; A = Bit Set with new pixel pos. +; used : AF, HL + + +SP.PixelLeft: + rlca ; Sets new pixel bit 1 to the right + ret nc + ex af, af' ; Signal in C' we've moved off current ATTR cell + ld a,l + dec a + ld l,a + cp 32 ; Carry if in screen + ccf + ld a, 1 + ret + #line 16 "draw.asm" #line 1 "PixelRight.asm" - - ; - ; PixelRight - ; Jose Rodriguez 2012 - ; - - - ; PixelRight - ; - ; Adjusts screen address HL and Pixel bit A to move one pixel to the left - ; on the display. Start of line set Carry (Out of Screen) - ; -; enter: HL = valid screen address - ; A = Bit Set -; exit : Carry = moved off screen - ; Carry' Set if moved off current ATTR CELL - ; HL = moves one character left, if needed - ; A = Bit Set with new pixel pos. -; used : AF, HL - - -SP.PixelRight: - rrca ; Sets new pixel bit 1 to the right - ret nc - ex af, af' ; Signal in C' we've moved off current ATTR cell - ld a, l - inc a - ld l, a - cp 32 ; Carry if IN screen - ccf - ld a, 80h - ret - + + ; + ; PixelRight + ; Jose Rodriguez 2012 + ; + + + ; PixelRight + ; + ; Adjusts screen address HL and Pixel bit A to move one pixel to the left + ; on the display. Start of line set Carry (Out of Screen) + ; +; enter: HL = valid screen address + ; A = Bit Set +; exit : Carry = moved off screen + ; Carry' Set if moved off current ATTR CELL + ; HL = moves one character left, if needed + ; A = Bit Set with new pixel pos. +; used : AF, HL + + +SP.PixelRight: + rrca ; Sets new pixel bit 1 to the right + ret nc + ex af, af' ; Signal in C' we've moved off current ATTR cell + ld a, l + inc a + ld l, a + cp 32 ; Carry if IN screen + ccf + ld a, 80h + ret + #line 17 "draw.asm" - + ;; DRAW PROCEDURE - PROC - + PROC + LOCAL __DRAW1 LOCAL __DRAW2 LOCAL __DRAW3 @@ -577,22 +577,22 @@ SP.PixelRight: LOCAL __INCX, __INCY, __DECX, __DECY LOCAL P_FLAG P_FLAG EQU 23697 - + __DRAW_ERROR: jp __OUT_OF_SCREEN_ERR - + DRAW: ;; ENTRY POINT - + LOCAL PIXEL_ADDR LOCAL COORDS LOCAL __DRAW_SETUP1, __DRAW_START, __PLOTOVER, __PLOTINVERSE - + ex de, hl ; DE = Y OFFSET pop hl ; return addr ex (sp), hl ; CALLEE => HL = X OFFSET ld bc, (COORDS) - + ld a, c add a, l ld l, a @@ -600,26 +600,26 @@ DRAW: adc a, 0 ; HL = HL + C ld h, a jr nz, __DRAW_ERROR ; if a <> 0 => Out of Screen - + ld a, b add a, e - ld e, a + ld e, a ld a, d adc a, 0 ; DE = DE + B ld d, a jr nz, __DRAW_ERROR ; if a <> 0 => Out of Screen - + ld a, 191 sub e jr c, __DRAW_ERROR ; Out of screen - + ld h, e ; now H,L = y2, x2 - + __DRAW: ; __FASTCALL__ Entry. Plots from (COORDS) to coord H, L push hl ex de, hl ; D,E = y2, x2; - + ld a, (P_FLAG) ld c, a bit 2, a ; Test for INVERSE1 @@ -628,7 +628,7 @@ __DRAW: ld (__PLOTINVERSE), a ld a, 0A6h ; and (hl) jp __DRAW_START - + __DRAW_SETUP1: xor a ; nop ld (__PLOTINVERSE), a @@ -636,7 +636,7 @@ __DRAW_SETUP1: bit 0, c ; Test for OVER jr z, __DRAW_START ld a, 0AEh ; xor (hl) - + __DRAW_START: ld (__PLOTOVER), a ; "Pokes" last operation exx @@ -646,7 +646,7 @@ __DRAW_START: LOCAL __PIXEL_ADDR __PIXEL_ADDR EQU 22ACh call __PIXEL_ADDR - + ;; Now gets pixel mask in A register ld b, a inc b @@ -656,7 +656,7 @@ __DRAW_START: __PIXEL_MASK: rra djnz __PIXEL_MASK - + ld b, d ; Restores B' from D' pop de ; D'E' = y2, x2 exx ; At this point: D'E' = y2,x2 coords @@ -664,147 +664,147 @@ __PIXEL_MASK: ex af, af' ; Saves A reg for later ; A' = Pixel mask ; H'L' = Screen Address of pixel - + ld bc, (COORDS) ; B,C = y1, x1 - - ld a, e + + ld a, e sub c ; dx = X2 - X1 ld c, a ; Saves dx in c - + ld a, 0Ch ; INC C opcode ld hl, __INCX ; xi = 1 jr nc, __DRAW1 - + ld a, c neg ; dx = X1 - X2 ld c, a ld a, 0Dh ; DEC C opcode ld hl, __DECX ; xi = -1 - + __DRAW1: ld (DX1), a ld (DX1 + 2), hl ; Updates DX1 call address ld (DX2), a ld (DX2 + 2), hl ; Updates DX2 call address - + ld a, d sub b ; dy = Y2 - Y1 ld b, a ; Saves dy in b - + ld a, 4 ; INC B opcode ld hl, __INCY ; y1 = 1 jr nc, __DRAW2 - + ld a, b neg ld b, a ; dy = Y2 - Y1 ld a, 5 ; DEC B opcode ld hl, __DECY ; y1 = -1 - + __DRAW2: ld (DY1), a ld (DY1 + 2), hl ; Updates DX1 call address ld (DY2), a ld (DY2 + 2), hl ; Updates DX2 call address - + ld a, b sub c ; dy - dx jr c, __DRAW_DX_GT_DY ; DX > DY - + ; At this point DY >= DX ; -------------------------- ; HL = error = dY / 2 ld h, 0 ld l, b srl l - + ; DE = -dX xor a sub c ld e, a sbc a, a ld d, a - + ; BC = DY ld c, b ld b, h - + exx scf ; Sets Carry to signal update ATTR ex af, af' ; Brings back pixel mask ld e, a ; Saves it in free E register jp __DRAW4_LOOP - + __DRAW3: ; While c != e => while y != y2 exx add hl, de ; error -= dX bit 7, h ; exx ; recover coordinates - jr z, __DRAW4 ; if error < 0 - + jr z, __DRAW4 ; if error < 0 + exx - add hl, bc ; error += dY + add hl, bc ; error += dY exx - + ld a, e DX1: ; x += xi inc c call __INCX ; This address will be dynamically updated ld e, a - + __DRAW4: - + DY1: ; y += yi inc b call __INCY ; This address will be dyncamically updated ld a, e ; Restores A reg. call __FASTPLOT - + __DRAW4_LOOP: ld a, b cp d jp nz, __DRAW3 ld (COORDS), bc - ret - + ret + __DRAW_DX_GT_DY: ; DX > DY ; -------------------------- ; HL = error = dX / 2 ld h, 0 - ld l, c + ld l, c srl l ; HL = error = DX / 2 - + ; DE = -dY xor a sub b ld e, a sbc a, a ld d, a - + ; BC = dX ld b, h - + exx ld d, e scf ; Sets Carry to signal update ATTR ex af, af' ; Brings back pixel mask ld e, a ; Saves it in free E register jp __DRAW6_LOOP - + __DRAW5: ; While loop exx add hl, de ; error -= dY bit 7, h ; if (error < 0) exx ; Restore coords - jr z, __DRAW6 ; + jr z, __DRAW6 ; exx add hl, bc ; error += dX - exx - + exx + DY2: ; y += yi inc b call __INCY ; This address will be dynamically updated - + __DRAW6: ld a, e DX2: ; x += xi @@ -812,40 +812,40 @@ DX2: ; x += xi call __INCX ; This address will be dynamically updated ld e, a call __FASTPLOT - + __DRAW6_LOOP: ld a, c ; Current X coord cp d jp nz, __DRAW5 ld (COORDS), bc ret - - PIXEL_ADDR EQU 22ACh + + PIXEL_ADDR EQU 22ACh COORDS EQU 5C7Dh - + __DRAW_END: exx ret - + ;; Given a A mask and an HL screen position ;; return the next left position ;; Also updates BC coords __DECX EQU SP.PixelLeft - + ;; Like the above, but to the RIGHT ;; Also updates BC coords __INCX EQU SP.PixelRight - + ;; Given an HL screen position, calculates ;; the above position ;; Also updates BC coords __INCY EQU SP.PixelUp - + ;; Given an HL screen position, calculates ;; the above position ;; Also updates BC coords __DECY EQU SP.PixelDown - + ;; Puts the A register MASK in (HL) __FASTPLOT: __PLOTINVERSE: @@ -853,12 +853,12 @@ __PLOTINVERSE: __PLOTOVER: or (hl) ; Replace with XOR (hl) if OVER 1 AND INVERSE 0 ; Replace with AND (hl) if INVERSE 1 - + ld (hl), a ex af, af' ; Recovers flag. If Carry set => update ATTR ld a, e ; Recovers A reg ret nc - + push hl push de ;; gets ATTR position with offset given in SCREEN_ADDR @@ -871,29 +871,29 @@ __PLOTOVER: ld h, a ld de, (SCREEN_ADDR) add hl, de ;; Final screen addr - + LOCAL PO_ATTR_2 PO_ATTR_2 EQU 0BE4h ; Another entry to PO_ATTR call PO_ATTR_2 ; This will update attr accordingly. Beware, uses IY - + pop de pop hl - - LOCAL __FASTPLOTEND -__FASTPLOTEND: + + LOCAL __FASTPLOTEND +__FASTPLOTEND: or a ; Resets carry flag ex af, af' ; Recovers A reg ld a, e ret - + ENDP - + #line 14 "draw3.asm" - + ; Ripped from the ZX Spectrum ROM - + DRAW3: - PROC + PROC LOCAL STACK_TO_BC LOCAL STACK_TO_A LOCAL COORDS @@ -904,12 +904,12 @@ DRAW3: LOCAL L23C1 LOCAL L2D28 LOCAL SUM_C, SUM_B - + L2D28 EQU 02D28h COORDS EQU 5C7Dh STACK_TO_BC EQU 2307h STACK_TO_A EQU 2314h - + exx ex af, af' ;; Preserves ARC pop hl @@ -922,14 +922,14 @@ DRAW3: exx ex af, af' call __FPSTACK_PUSH ;; R Arc - - ; Now enter the calculator and store the complete rotation angle in mem-5 - + + ; Now enter the calculator and store the complete rotation angle in mem-5 + RST 28H ;; FP-CALC x, y, A. DEFB $C5 ;;st-mem-5 x, y, A. - + ; Test the angle for the special case of 360 degrees. - + DEFB $A2 ;;stk-half x, y, A, 1/2. DEFB $04 ;;multiply x, y, A/2. DEFB $1F ;;sin x, y, sin(A/2). @@ -937,39 +937,39 @@ DRAW3: DEFB $30 ;;not x, y, sin(A/2), (0/1). DEFB $30 ;;not x, y, sin(A/2), (1/0). DEFB $00 ;;jump-true x, y, sin(A/2). - + DEFB $06 ;;forward to L23A3, DR-SIN-NZ ;;if sin(r/2) is not zero. - + ; The third parameter is 2*PI (or a multiple of 2*PI) so a 360 degrees turn - ; would just be a straight line. Eliminating this case here prevents + ; would just be a straight line. Eliminating this case here prevents ; division by zero at later stage. - + DEFB $02 ;;delete x, y. DEFB $38 ;;end-calc x, y. JP L2477 - + ; --- - + ; An arc can be drawn. - + ;; DR-SIN-NZ DEFB $C0 ;;st-mem-0 x, y, sin(A/2). store mem-0 DEFB $02 ;;delete x, y. - - ; The next step calculates (roughly) the diameter of the circle of which the + + ; The next step calculates (roughly) the diameter of the circle of which the ; arc will form part. This value does not have to be too accurate as it is ; only used to evaluate the number of straight lines and then discarded. - ; After all for a circle, the radius is used. Consequently, a circle of + ; After all for a circle, the radius is used. Consequently, a circle of ; radius 50 will have 24 straight lines but an arc of radius 50 will have 20 ; straight lines - when drawn in any direction. - ; So that simple arithmetic can be used, the length of the chord can be + ; So that simple arithmetic can be used, the length of the chord can be ; calculated as X+Y rather than by Pythagoras Theorem and the sine of the ; nearest angle within reach is used. - + DEFB $C1 ;;st-mem-1 x, y. store mem-1 DEFB $02 ;;delete x. - + DEFB $31 ;;duplicate x, x. DEFB $2A ;;abs x, x (+ve). DEFB $E1 ;;get-mem-1 x, X, y. @@ -980,103 +980,103 @@ DRAW3: DEFB $E0 ;;get-mem-0 x, y, X+Y, sin(A/2). DEFB $05 ;;division x, y, X+Y/sin(A/2). DEFB $2A ;;abs x, y, X+Y/sin(A/2) = D. - + ; Bring back sin(A/2) from mem-0 which will shortly get trashed. ; Then bring D to the top of the stack again. - + DEFB $E0 ;;get-mem-0 x, y, D, sin(A/2). DEFB $01 ;;exchange x, y, sin(A/2), D. - + ; Note. that since the value at the top of the stack has arisen as a result ; of division then it can no longer be in integer form and the next re-stack ; is unnecessary. Only the Sinclair ZX80 had integer division. - + ;;DEFB $3D ;;re-stack (unnecessary) - + DEFB $38 ;;end-calc x, y, sin(A/2), D. - + ; The next test avoids drawing 4 straight lines when the start and end pixels ; are adjacent (or the same) but is probably best dispensed with. - + LD A,(HL) ; fetch exponent byte of D. CP $81 ; compare to 1 JR NC,L23C1 ; forward, if > 1, to DR-PRMS - + ; else delete the top two stack values and draw a simple straight line. - + RST 28H ;; FP-CALC DEFB $02 ;;delete DEFB $02 ;;delete DEFB $38 ;;end-calc x, y. - + JP L2477 ; to LINE-DRAW - + ; --- - + ; The ARC will consist of multiple straight lines so call the CIRCLE-DRAW ; PARAMETERS ROUTINE to pre-calculate sine values from the angle (in mem-5) ; and determine also the number of straight lines from that value and the ; 'diameter' which is at the top of the calculator stack. - + ;; DR-PRMS L23C1: CALL 247Dh ; routine CD-PRMS1 - + ; mem-0 ; (A)/No. of lines (=a) (step angle) - ; mem-1 ; sin(a/2) + ; mem-1 ; sin(a/2) ; mem-2 ; - ; mem-3 ; cos(a) const ; mem-4 ; sin(a) const ; mem-5 ; Angle of rotation (A) in ; B ; Count of straight lines - max 252. - + PUSH BC ; Save the line count on the machine stack. - + ; Remove the now redundant diameter value D. - + RST 28H ;; FP-CALC x, y, sin(A/2), D. DEFB $02 ;;delete x, y, sin(A/2). - + ; Dividing the sine of the step angle by the sine of the total angle gives ; the length of the initial chord on a unary circle. This factor f is used - ; to scale the coordinates of the first line which still points in the + ; to scale the coordinates of the first line which still points in the ; direction of the end point and may be larger. - + DEFB $E1 ;;get-mem-1 x, y, sin(A/2), sin(a/2) DEFB $01 ;;exchange x, y, sin(a/2), sin(A/2) DEFB $05 ;;division x, y, sin(a/2)/sin(A/2) DEFB $C1 ;;st-mem-1 x, y. f. DEFB $02 ;;delete x, y. - + ; With the factor stored, scale the x coordinate first. - + DEFB $01 ;;exchange y, x. DEFB $31 ;;duplicate y, x, x. DEFB $E1 ;;get-mem-1 y, x, x, f. DEFB $04 ;;multiply y, x, x*f (=xx) DEFB $C2 ;;st-mem-2 y, x, xx. DEFB $02 ;;delete y. x. - + ; Now scale the y coordinate. - + DEFB $01 ;;exchange x, y. DEFB $31 ;;duplicate x, y, y. DEFB $E1 ;;get-mem-1 x, y, y, f DEFB $04 ;;multiply x, y, y*f (=yy) - - ; Note. 'sin' and 'cos' trash locations mem-0 to mem-2 so fetch mem-2 to the + + ; Note. 'sin' and 'cos' trash locations mem-0 to mem-2 so fetch mem-2 to the ; calculator stack for safe keeping. - + DEFB $E2 ;;get-mem-2 x, y, yy, xx. - + ; Once we get the coordinates of the first straight line then the 'ROTATION ; FORMULA' used in the arc loop will take care of all other points, but we ; now use a variation of that formula to rotate the first arc through (A-a)/2 - ; radians. - ; + ; radians. + ; ; xRotated = y * sin(angle) + x * cos(angle) ; yRotated = y * cos(angle) - x * sin(angle) ; - + DEFB $E5 ;;get-mem-5 x, y, yy, xx, A. DEFB $E0 ;;get-mem-0 x, y, yy, xx, A, a. DEFB $03 ;;subtract x, y, yy, xx, A-a. @@ -1086,17 +1086,17 @@ L23C1: CALL 247Dh ; routine CD-PRMS1 DEFB $1F ;;sin x, y, yy, xx, angle, sin(angle) DEFB $C5 ;;st-mem-5 x, y, yy, xx, angle, sin(angle) DEFB $02 ;;delete x, y, yy, xx, angle - + DEFB $20 ;;cos x, y, yy, xx, cos(angle). - + ; Note. mem-0, mem-1 and mem-2 can be used again now... - + DEFB $C0 ;;st-mem-0 x, y, yy, xx, cos(angle). DEFB $02 ;;delete x, y, yy, xx. - + DEFB $C2 ;;st-mem-2 x, y, yy, xx. DEFB $02 ;;delete x, y, yy. - + DEFB $C1 ;;st-mem-1 x, y, yy. DEFB $E5 ;;get-mem-5 x, y, yy, sin(angle) DEFB $04 ;;multiply x, y, yy*sin(angle). @@ -1108,7 +1108,7 @@ L23C1: CALL 247Dh ; routine CD-PRMS1 DEFB $01 ;;exchange x, y, yy, xRotated. DEFB $C1 ;;st-mem-1 x, y, yy, xRotated. DEFB $02 ;;delete x, y, yy. - + DEFB $E0 ;;get-mem-0 x, y, yy, cos(angle). DEFB $04 ;;multiply x, y, yy*cos(angle). DEFB $E2 ;;get-mem-2 x, y, yy*cos(angle), xx. @@ -1116,131 +1116,131 @@ L23C1: CALL 247Dh ; routine CD-PRMS1 DEFB $04 ;;multiply x, y, yy*cos(angle), xx*sin(angle). DEFB $03 ;;subtract x, y, yRotated. DEFB $C2 ;;st-mem-2 x, y, yRotated. - - ; Now the initial x and y coordinates are made positive and summed to see + + ; Now the initial x and y coordinates are made positive and summed to see ; if they measure up to anything significant. - + DEFB $2A ;;abs x, y, yRotated'. DEFB $E1 ;;get-mem-1 x, y, yRotated', xRotated. DEFB $2A ;;abs x, y, yRotated', xRotated'. DEFB $0F ;;addition x, y, yRotated+xRotated. - DEFB $02 ;;delete x, y. - - DEFB $38 ;;end-calc x, y. - + DEFB $02 ;;delete x, y. + + DEFB $38 ;;end-calc x, y. + ; Although the test value has been deleted it is still above the calculator ; stack in memory and conveniently DE which points to the first free byte ; addresses the exponent of the test value. - + LD A,(DE) ; Fetch exponent of the length indicator. CP $81 ; Compare to that for 1 - + POP BC ; Balance the machine stack - + JP C,L2477 ; forward, if the coordinates of first line - ; don't add up to more than 1, to LINE-DRAW - + ; don't add up to more than 1, to LINE-DRAW + ; Continue when the arc will have a discernable shape. - + PUSH BC ; Restore line counter to the machine stack. - - ; The parameters of the DRAW command were relative and they are now converted - ; to absolute coordinates by adding to the coordinates of the last point - ; plotted. The first two values on the stack are the terminal tx and ty - ; coordinates. The x-coordinate is converted first but first the last point - ; plotted is saved as it will initialize the moving ax, value. - + + ; The parameters of the DRAW command were relative and they are now converted + ; to absolute coordinates by adding to the coordinates of the last point + ; plotted. The first two values on the stack are the terminal tx and ty + ; coordinates. The x-coordinate is converted first but first the last point + ; plotted is saved as it will initialize the moving ax, value. + RST 28H ;; FP-CALC x, y. DEFB $01 ;;exchange y, x. DEFB $38 ;;end-calc y, x. - + LD A,(COORDS) ;; Fetch System Variable COORDS-x CALL L2D28 ;; routine STACK-A - + RST 28H ;; FP-CALC y, x, last-x. - + ; Store the last point plotted to initialize the moving ax value. - + DEFB $C0 ;;st-mem-0 y, x, last-x. DEFB $0F ;;addition y, absolute x. DEFB $01 ;;exchange tx, y. DEFB $38 ;;end-calc tx, y. - + LD A,(COORDS + 1) ; Fetch System Variable COORDS-y CALL L2D28 ; routine STACK-A - + RST 28H ;; FP-CALC tx, y, last-y. - + ; Store the last point plotted to initialize the moving ay value. - + DEFB $C5 ;;st-mem-5 tx, y, last-y. DEFB $0F ;;addition tx, ty. - + ; Fetch the moving ax and ay to the calculator stack. - + DEFB $E0 ;;get-mem-0 tx, ty, ax. DEFB $E5 ;;get-mem-5 tx, ty, ax, ay. DEFB $38 ;;end-calc tx, ty, ax, ay. - + POP BC ; Restore the straight line count. - + ; ----------------------------------- ; THE 'CIRCLE/DRAW CONVERGENCE POINT' ; ----------------------------------- - ; The CIRCLE and ARC-DRAW commands converge here. + ; The CIRCLE and ARC-DRAW commands converge here. ; - ; Note. for both the CIRCLE and ARC commands the minimum initial line count - ; is 4 (as set up by the CD_PARAMS routine) and so the zero flag will never + ; Note. for both the CIRCLE and ARC commands the minimum initial line count + ; is 4 (as set up by the CD_PARAMS routine) and so the zero flag will never ; be set and the loop is always entered. The first test is superfluous and ; the jump will always be made to ARC-START. - + ;; DRW-STEPS -L2420: DEC B ; decrement the arc count (4,8,12,16...). - +L2420: DEC B ; decrement the arc count (4,8,12,16...). + ;JR Z,L245F ; forward, if zero (not possible), to ARC-END - + JP L2439 ; forward to ARC-START - + ; -------------- ; THE 'ARC LOOP' ; -------------- ; - ; The arc drawing loop will draw up to 31 straight lines for a circle and up + ; The arc drawing loop will draw up to 31 straight lines for a circle and up ; 251 straight lines for an arc between two points. In both cases the final - ; closing straight line is drawn at ARC_END, but it otherwise loops back to + ; closing straight line is drawn at ARC_END, but it otherwise loops back to ; here to calculate the next coordinate using the ROTATION FORMULA where (a) ; is the previously calculated, constant CENTRAL ANGLE of the arcs. ; ; Xrotated = x * cos(a) - y * sin(a) ; Yrotated = x * sin(a) + y * cos(a) ; - ; The values cos(a) and sin(a) are pre-calculated and held in mem-3 and mem-4 + ; The values cos(a) and sin(a) are pre-calculated and held in mem-3 and mem-4 ; for the duration of the routine. ; Memory location mem-1 holds the last relative x value (rx) and mem-2 holds ; the last relative y value (ry) used by DRAW. ; ; Note. that this is a very clever twist on what is after all a very clever, ; well-used formula. Normally the rotation formula is used with the x and y - ; coordinates from the centre of the circle (or arc) and a supplied angle to - ; produce two new x and y coordinates in an anticlockwise direction on the + ; coordinates from the centre of the circle (or arc) and a supplied angle to + ; produce two new x and y coordinates in an anticlockwise direction on the ; circumference of the circle. ; What is being used here, instead, is the relative X and Y parameters from - ; the last point plotted that are required to get to the current point and - ; the formula returns the next relative coordinates to use. - + ; the last point plotted that are required to get to the current point and + ; the formula returns the next relative coordinates to use. + ;; ARC-LOOP -L2425: RST 28H ;; FP-CALC +L2425: RST 28H ;; FP-CALC DEFB $E1 ;;get-mem-1 rx. DEFB $31 ;;duplicate rx, rx. DEFB $E3 ;;get-mem-3 cos(a) DEFB $04 ;;multiply rx, rx*cos(a). DEFB $E2 ;;get-mem-2 rx, rx*cos(a), ry. - DEFB $E4 ;;get-mem-4 rx, rx*cos(a), ry, sin(a). + DEFB $E4 ;;get-mem-4 rx, rx*cos(a), ry, sin(a). DEFB $04 ;;multiply rx, rx*cos(a), ry*sin(a). DEFB $03 ;;subtract rx, rx*cos(a) - ry*sin(a) DEFB $C1 ;;st-mem-1 rx, new relative x rotated. DEFB $02 ;;delete rx. - + DEFB $E4 ;;get-mem-4 rx, sin(a). DEFB $04 ;;multiply rx*sin(a) DEFB $E2 ;;get-mem-2 rx*sin(a), ry. @@ -1249,51 +1249,51 @@ L2425: RST 28H ;; FP-CALC DEFB $0F ;;addition rx*sin(a) + ry*cos(a). DEFB $C2 ;;st-mem-2 new relative y rotated. DEFB $02 ;;delete . - DEFB $38 ;;end-calc . - + DEFB $38 ;;end-calc . + ; Note. the calculator stack actually holds tx, ty, ax, ay - ; and the last absolute values of x and y + ; and the last absolute values of x and y ; are now brought into play. ; ; Magically, the two new rotated coordinates rx and ry are all that we would ; require to draw a circle or arc - on paper! - ; The Spectrum DRAW routine draws to the rounded x and y coordinate and so - ; repetitions of values like 3.49 would mean that the fractional parts - ; would be lost until eventually the draw coordinates might differ from the + ; The Spectrum DRAW routine draws to the rounded x and y coordinate and so + ; repetitions of values like 3.49 would mean that the fractional parts + ; would be lost until eventually the draw coordinates might differ from the ; floating point values used above by several pixels. - ; For this reason the accurate offsets calculated above are added to the - ; accurate, absolute coordinates maintained in ax and ay and these new - ; coordinates have the integer coordinates of the last plot position - ; ( from System Variable COORDS ) subtracted from them to give the relative + ; For this reason the accurate offsets calculated above are added to the + ; accurate, absolute coordinates maintained in ax and ay and these new + ; coordinates have the integer coordinates of the last plot position + ; ( from System Variable COORDS ) subtracted from them to give the relative ; coordinates required by the DRAW routine. - + ; The mid entry point. - + ;; ARC-START L2439: PUSH BC ; Preserve the arc counter on the machine stack. - + ; Store the absolute ay in temporary variable mem-0 for the moment. - + RST 28H ;; FP-CALC ax, ay. DEFB $C0 ;;st-mem-0 ax, ay. DEFB $02 ;;delete ax. - + ; Now add the fractional relative x coordinate to the fractional absolute ; x coordinate to obtain a new fractional x-coordinate. - + DEFB $E1 ;;get-mem-1 ax, xr. - DEFB $0F ;;addition ax+xr (= new ax). + DEFB $0F ;;addition ax+xr (= new ax). DEFB $31 ;;duplicate ax, ax. - DEFB $38 ;;end-calc ax, ax. - + DEFB $38 ;;end-calc ax, ax. + LD A,(COORDS) ; COORDS-x last x (integer ix 0-255) CALL L2D28 ; routine STACK-A - + RST 28H ;; FP-CALC ax, ax, ix. DEFB $03 ;;subtract ax, ax-ix = relative DRAW Dx. - + ; Having calculated the x value for DRAW do the same for the y value. - + DEFB $E0 ;;get-mem-0 ax, Dx, ay. DEFB $E2 ;;get-mem-2 ax, Dx, ay, ry. DEFB $0F ;;addition ax, Dx, ay+ry (= new ay). @@ -1301,59 +1301,59 @@ L2439: PUSH BC ; Preserve the arc counter on the machine stack. DEFB $01 ;;exchange ax, ay, Dx, DEFB $E0 ;;get-mem-0 ax, ay, Dx, ay. DEFB $38 ;;end-calc ax, ay, Dx, ay. - + LD A,(COORDS + 1) ; COORDS-y last y (integer iy 0-175) CALL L2D28 ; routine STACK-A - + RST 28H ;; FP-CALC ax, ay, Dx, ay, iy. DEFB $03 ;;subtract ax, ay, Dx, ay-iy ( = Dy). DEFB $38 ;;end-calc ax, ay, Dx, Dy. - + CALL L2477 ; Routine DRAW-LINE draws (Dx,Dy) relative to - ; the last pixel plotted leaving absolute x + ; the last pixel plotted leaving absolute x ; and y on the calculator stack. ; ax, ay. - + POP BC ; Restore the arc counter from the machine stack. - + DJNZ L2425 ; Decrement and loop while > 0 to ARC-LOOP - + ; ------------- ; THE 'ARC END' ; ------------- - + ; To recap the full calculator stack is tx, ty, ax, ay. - + ; Just as one would do if drawing the curve on paper, the final line would - ; be drawn by joining the last point plotted to the initial start point - ; in the case of a CIRCLE or to the calculated end point in the case of + ; be drawn by joining the last point plotted to the initial start point + ; in the case of a CIRCLE or to the calculated end point in the case of ; an ARC. ; The moving absolute values of x and y are no longer required and they ; can be deleted to expose the closing coordinates. - + ;; ARC-END L245F: RST 28H ;; FP-CALC tx, ty, ax, ay. DEFB $02 ;;delete tx, ty, ax. DEFB $02 ;;delete tx, ty. DEFB $01 ;;exchange ty, tx. DEFB $38 ;;end-calc ty, tx. - + ; First calculate the relative x coordinate to the end-point. - + LD A,($5C7D) ; COORDS-x CALL L2D28 ; routine STACK-A - + RST 28H ;; FP-CALC ty, tx, coords_x. DEFB $03 ;;subtract ty, rx. - + ; Next calculate the relative y coordinate to the end-point. - + DEFB $01 ;;exchange rx, ty. DEFB $38 ;;end-calc rx, ty. - + LD A,($5C7E) ; COORDS-y CALL L2D28 ; routine STACK-A - + RST 28H ;; FP-CALC rx, ty, coords_y DEFB $03 ;;subtract rx, ry. DEFB $38 ;;end-calc rx, ry. @@ -1361,7 +1361,7 @@ L245F: RST 28H ;; FP-CALC tx, ty, ax, ay. L2477: call STACK_TO_BC ;;Pops x, and y, and stores it in B, C ld hl, (COORDS) ;;Calculates x2 and y2 in L, H - + rl e ;; Rotate left to carry ld a, c jr nc, SUM_C @@ -1369,7 +1369,7 @@ L2477: SUM_C: add a, l ld l, a ;; X2 - + rl d ;; Low sign to carry ld a, b jr nc, SUM_B @@ -1378,56 +1378,56 @@ SUM_B: add a, h ld h, a jp __DRAW ;;forward to LINE-DRAW (Fastcalled) - + ENDP #line 76 "draw3.bas" #line 1 "ftou32reg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "ftou32reg.asm" - + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) PROC - + LOCAL __IS_FLOAT - + or a - jr nz, __IS_FLOAT + jr nz, __IS_FLOAT ; Here if it is a ZX ROM Integer - + ld h, c ld l, d ld a, e ; Takes sign: FF = -, 0 = + @@ -1435,64 +1435,64 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS inc a jp z, __NEG32 ; Negates if negative ret - + __IS_FLOAT: ; Jumps here if it is a true floating point number - ld h, e + ld h, e push hl ; Stores it for later (Contains Sign in H) - + push de push bc - + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + ;ld a, c ; Get exponent sub 128 ; Exponent -= 128 jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 - + __FTOU32REG_LOOP: exx ; Shift C'B' E'D' << 1, output bit stays in Carry sla d rl e rl b rl c - + exx ; Shift DEHL << 1, inserting the carry on the right rl l rl h rl e rl d - + djnz __FTOU32REG_LOOP - + __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative jp m, __NEG32 ; Negates DEHL - + ret - + ENDP - - + + __FTOU8: ; Converts float in C ED LH to Unsigned byte in A call __FTOU32REG ld a, l ret - + #line 77 "draw3.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00, 00 diff --git a/tests/functional/einar01.asm b/tests/functional/einar01.asm index 6e2457f2c..edf14cd2d 100644 --- a/tests/functional/einar01.asm +++ b/tests/functional/einar01.asm @@ -28,7 +28,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _score: DEFW 0000h diff --git a/tests/functional/einarattr.asm b/tests/functional/einarattr.asm index 80fdb91d2..1fe316dcd 100644 --- a/tests/functional/einarattr.asm +++ b/tests/functional/einarattr.asm @@ -57,20 +57,20 @@ __LABEL1: DEFW 0001h DEFB 41h #line 1 "copy_attr.asm" - - + + #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -78,46 +78,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -130,43 +130,43 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -174,12 +174,12 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -187,51 +187,51 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "in_screen.asm" - + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -240,17 +240,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -258,26 +258,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -291,45 +291,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -340,28 +340,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -369,28 +369,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -399,41 +399,41 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register - - - + + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -443,7 +443,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -451,20 +451,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -474,7 +474,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -485,19 +485,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -507,7 +507,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -518,19 +518,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -540,7 +540,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -553,22 +553,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -577,79 +577,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -658,75 +658,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -736,7 +736,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -748,16 +748,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -771,49 +771,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -824,17 +824,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -847,27 +847,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -875,10 +875,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -895,80 +895,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -985,8 +985,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1010,17 +1010,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1031,7 +1031,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1041,21 +1041,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1074,9 +1074,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1101,72 +1101,72 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 3 "copy_attr.asm" #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -1175,22 +1175,22 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 44 "einarattr.bas" - - + + #line 1 "printstr.asm" - - - - + + + + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1198,25 +1198,25 @@ __REFRESH_TMP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1225,41 +1225,41 @@ __REFRESH_TMP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1267,25 +1267,25 @@ __REFRESH_TMP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1294,39 +1294,39 @@ __REFRESH_TMP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -1334,56 +1334,56 @@ __REFRESH_TMP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -1392,57 +1392,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -1451,47 +1451,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -1501,51 +1501,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 5 "printstr.asm" - + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1554,11 +1554,11 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 47 "einarattr.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/einarshift.asm b/tests/functional/einarshift.asm index 62f00bb45..df937ada5 100644 --- a/tests/functional/einarshift.asm +++ b/tests/functional/einarshift.asm @@ -42,17 +42,17 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -60,46 +60,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -112,43 +112,43 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -156,12 +156,12 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -169,51 +169,51 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "in_screen.asm" - + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -222,17 +222,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -240,26 +240,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -273,45 +273,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -322,28 +322,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -351,28 +351,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -381,83 +381,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -466,32 +466,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -501,7 +501,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -509,20 +509,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -532,7 +532,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -543,19 +543,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -565,7 +565,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -576,19 +576,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -598,7 +598,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -611,22 +611,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -635,79 +635,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -716,75 +716,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -794,7 +794,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -806,16 +806,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -829,49 +829,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -882,17 +882,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -905,27 +905,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -933,10 +933,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -953,80 +953,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1043,8 +1043,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1068,17 +1068,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1089,7 +1089,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1099,21 +1099,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1132,9 +1132,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1159,33 +1159,33 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 32 "einarshift.bas" #line 1 "printu8.asm" - + #line 1 "printi8.asm" - + #line 1 "printnum.asm" - - - - + + + + __PRINTU_START: PROC - + LOCAL __PRINTU_CONT - + ld a, b or a jp nz, __PRINTU_CONT - + ld a, '0' jp __PRINT_DIGIT - - + + __PRINTU_CONT: pop af push bc @@ -1193,63 +1193,63 @@ __PRINTU_CONT: pop bc djnz __PRINTU_CONT ret - + ENDP - - + + __PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers ld a, '-' jp __PRINT_DIGIT - + __PRINT_DIGIT EQU __PRINTCHAR ; PRINTS the char in A register, and puts its attrs - - + + #line 2 "printi8.asm" #line 1 "div8.asm" - + ; -------------------------------- -__DIVU8: ; 8 bit unsigned integer division +__DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A pop hl ; -------------------------------- ex (sp), hl ; CALLEE - + __DIVU8_FAST: ; Does A / H ld l, h ld h, a ; At this point do H / L - + ld b, 8 xor a ; A = 0, Carry Flag = 0 - + __DIV8LOOP: - sla h - rla - cp l + sla h + rla + cp l jr c, __DIV8NOSUB - sub l - inc h - -__DIV8NOSUB: + sub l + inc h + +__DIV8NOSUB: djnz __DIV8LOOP - + ld l, a ; save remainder - ld a, h ; - - ret ; a = Quotient, - - + ld a, h ; + + ret ; a = Quotient, + + ; -------------------------------- __DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A pop hl ; -------------------------------- ex (sp), hl - + __DIVI8_FAST: ld e, a ; store operands for later ld c, h - + or a ; negative? jp p, __DIV8A neg ; Make it positive - + __DIV8A: ex af, af' ld a, h @@ -1257,84 +1257,84 @@ __DIV8A: jp p, __DIV8B neg ld h, a ; make it positive - + __DIV8B: ex af, af' - + call __DIVU8_FAST - + ld a, c xor l ; bit 7 of A = 1 if result is negative - + ld a, h ; Quotient - ret p ; return if positive - + ret p ; return if positive + neg ret - - + + __MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) pop hl ex (sp), hl ; CALLEE - + __MODU8_FAST: ; __FASTCALL__ entry call __DIVU8_FAST ld a, l ; Remainder - + ret ; a = Modulus - - + + __MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) pop hl ex (sp), hl ; CALLEE - + __MODI8_FAST: ; __FASTCALL__ entry call __DIVI8_FAST ld a, l ; remainder - + ret ; a = Modulus - + #line 3 "printi8.asm" - + __PRINTI8: ; Prints an 8 bits number in Accumulator (A) ; Converts 8 to 32 bits or a jp p, __PRINTU8 - + push af call __PRINT_MINUS pop af neg - + __PRINTU8: PROC - + LOCAL __PRINTU_LOOP - + ld b, 0 ; Counter - + __PRINTU_LOOP: or a jp z, __PRINTU_START - + push bc ld h, 10 call __DIVU8_FAST ; Divides by 10. D'E'H'L' contains modulo (L' since < 10) pop bc - + ld a, l or '0' ; Stores ASCII digit (must be print in reversed order) push af ld a, h inc b jp __PRINTU_LOOP ; Uses JP in loops - + ENDP - + #line 2 "printu8.asm" - + #line 33 "einarshift.bas" - + ZXBASIC_USER_DATA: _a: DEFB 03h diff --git a/tests/functional/elseif.asm b/tests/functional/elseif.asm index 5b509b7a9..671802e01 100644 --- a/tests/functional/elseif.asm +++ b/tests/functional/elseif.asm @@ -44,7 +44,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _num: DEFB 00 diff --git a/tests/functional/elseif1.asm b/tests/functional/elseif1.asm index 225aebe3f..237c470ee 100644 --- a/tests/functional/elseif1.asm +++ b/tests/functional/elseif1.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/elseif2.asm b/tests/functional/elseif2.asm index 225aebe3f..237c470ee 100644 --- a/tests/functional/elseif2.asm +++ b/tests/functional/elseif2.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/elseif3.asm b/tests/functional/elseif3.asm index 5bf6febb6..02ef0e9a3 100644 --- a/tests/functional/elseif3.asm +++ b/tests/functional/elseif3.asm @@ -43,9 +43,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "lti8.asm" - + #line 1 "lei8.asm" - + __LEI8: ; Signed <= comparison for 8bit int ; A <= H (registers) PROC @@ -54,10 +54,10 @@ __LEI8: ; Signed <= comparison for 8bit int jr nz, __LTI inc a ret - + __LTI8: ; Test 8 bit values A < H sub h - + __LTI: ; Generic signed comparison jp po, checkParity xor 0x80 @@ -69,7 +69,7 @@ checkParity: ENDP #line 2 "lti8.asm" #line 34 "elseif3.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/elseif4.asm b/tests/functional/elseif4.asm index 225aebe3f..237c470ee 100644 --- a/tests/functional/elseif4.asm +++ b/tests/functional/elseif4.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/elseif5.asm b/tests/functional/elseif5.asm index 1f5e8e0b2..597b198af 100644 --- a/tests/functional/elseif5.asm +++ b/tests/functional/elseif5.asm @@ -47,9 +47,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "lti8.asm" - + #line 1 "lei8.asm" - + __LEI8: ; Signed <= comparison for 8bit int ; A <= H (registers) PROC @@ -58,10 +58,10 @@ __LEI8: ; Signed <= comparison for 8bit int jr nz, __LTI inc a ret - + __LTI8: ; Test 8 bit values A < H sub h - + __LTI: ; Generic signed comparison jp po, checkParity xor 0x80 @@ -73,7 +73,7 @@ checkParity: ENDP #line 2 "lti8.asm" #line 38 "elseif5.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/elseif6.asm b/tests/functional/elseif6.asm index 14647a71e..667da2109 100644 --- a/tests/functional/elseif6.asm +++ b/tests/functional/elseif6.asm @@ -36,9 +36,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "lti8.asm" - + #line 1 "lei8.asm" - + __LEI8: ; Signed <= comparison for 8bit int ; A <= H (registers) PROC @@ -47,10 +47,10 @@ __LEI8: ; Signed <= comparison for 8bit int jr nz, __LTI inc a ret - + __LTI8: ; Test 8 bit values A < H sub h - + __LTI: ; Generic signed comparison jp po, checkParity xor 0x80 @@ -62,7 +62,7 @@ checkParity: ENDP #line 2 "lti8.asm" #line 27 "elseif6.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/emptystrparam.asm b/tests/functional/emptystrparam.asm index 537d57c80..acc669f63 100644 --- a/tests/functional/emptystrparam.asm +++ b/tests/functional/emptystrparam.asm @@ -55,10 +55,10 @@ _stringtest__leave: __LABEL0: DEFW 0000h #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -66,25 +66,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -93,41 +93,41 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -135,25 +135,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -162,39 +162,39 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -202,56 +202,56 @@ __LABEL0: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -260,57 +260,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -319,47 +319,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -369,17 +369,17 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 43 "emptystrparam.bas" #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -387,25 +387,25 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -414,51 +414,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -466,12 +466,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -479,16 +479,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -500,27 +500,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -532,7 +532,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -540,15 +540,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -573,14 +573,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -588,25 +588,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -615,37 +615,37 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) pop hl ; Recovers destiny in hl as result ret #line 44 "emptystrparam.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/end.asm b/tests/functional/end.asm index 14456c1dc..f7f8d7a68 100644 --- a/tests/functional/end.asm +++ b/tests/functional/end.asm @@ -30,7 +30,7 @@ __CALL_BACK__: ld b, h ld c, l jp __END_PROGRAM - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/eq0.asm b/tests/functional/eq0.asm index bb0242b94..2356d1cc5 100644 --- a/tests/functional/eq0.asm +++ b/tests/functional/eq0.asm @@ -34,41 +34,41 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "eqf.asm" - + #line 1 "u32tofreg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "u32tofreg.asm" __I8TOFREG: ld l, a @@ -77,35 +77,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -113,20 +113,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -134,46 +134,46 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 2 "eqf.asm" #line 1 "ftou32reg.asm" - - - + + + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) PROC - + LOCAL __IS_FLOAT - + or a - jr nz, __IS_FLOAT + jr nz, __IS_FLOAT ; Here if it is a ZX ROM Integer - + ld h, c ld l, d ld a, e ; Takes sign: FF = -, 0 = + @@ -181,96 +181,96 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS inc a jp z, __NEG32 ; Negates if negative ret - + __IS_FLOAT: ; Jumps here if it is a true floating point number - ld h, e + ld h, e push hl ; Stores it for later (Contains Sign in H) - + push de push bc - + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + ;ld a, c ; Get exponent sub 128 ; Exponent -= 128 jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 - + __FTOU32REG_LOOP: exx ; Shift C'B' E'D' << 1, output bit stays in Carry sla d rl e rl b rl c - + exx ; Shift DEHL << 1, inserting the carry on the right rl l rl h rl e rl d - + djnz __FTOU32REG_LOOP - + __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative jp m, __NEG32 ; Negates DEHL - + ret - + ENDP - - + + __FTOU8: ; Converts float in C ED LH to Unsigned byte in A call __FTOU32REG ld a, l ret - + #line 3 "eqf.asm" #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -286,39 +286,39 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 4 "eqf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) - + ; All of them uses C EDHL registers as 1st paramter. ; For binary operators, the 2n operator must be pushed into the ; stack, in the order BC DE HL (B not used). ; ; Uses CALLEE convention ; ------------------------------------------------------------- - - + + __EQF: ; A = B call __FPSTACK_PUSH2 - + ; ------------- ROM NOS-EQL ld b, 0Eh ; For comparison operators, OP must be in B also rst 28h defb 0Eh defb 38h; ; END CALC - - call __FPSTACK_POP + + call __FPSTACK_POP jp __FTOU8 ; Convert to 8 bits - + #line 25 "eq0.bas" #line 1 "pushf.asm" - - - ; Routine to push Float pointed by HL + + + ; Routine to push Float pointed by HL ; Into the stack. Notice that the hl points to the last ; byte of the FP number. ; Uses H'L' B'C' and D'E' to preserve ABCDEHL registers - + __FP_PUSH_REV: push hl exx @@ -339,10 +339,10 @@ __FP_PUSH_REV: push bc ; Return Address exx ret - - + + #line 26 "eq0.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/equ8.asm b/tests/functional/equ8.asm index e70c68b73..d9073e90d 100644 --- a/tests/functional/equ8.asm +++ b/tests/functional/equ8.asm @@ -33,7 +33,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/fastcall0.asm b/tests/functional/fastcall0.asm index 1d312f1f3..e860672a0 100644 --- a/tests/functional/fastcall0.asm +++ b/tests/functional/fastcall0.asm @@ -481,25 +481,25 @@ __LABEL0: DEFW 0001h DEFB 61h #line 1 "circle.asm" - + ; Bresenham's like circle algorithm ; best known as Middle Point Circle drawing algorithm - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -507,12 +507,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -520,7 +520,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -528,22 +528,22 @@ __STOP: ret #line 5 "circle.asm" #line 1 "plot.asm" - + ; MIXED __FASTCAL__ / __CALLE__ PLOT Function ; Plots a point into the screen calling the ZX ROM PLOT routine - + ; Y in A (accumulator) ; X in top of the stack - - + + #line 1 "in_screen.asm" - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -551,75 +551,75 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 2 "in_screen.asm" - - + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 9 "plot.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -632,48 +632,48 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 10 "plot.asm" - + PLOT: PROC - + LOCAL PLOT_SUB LOCAL PIXEL_ADDR LOCAL COORDS LOCAL __PLOT_ERR LOCAL P_FLAG LOCAL __PLOT_OVER1 - + P_FLAG EQU 23697 - + pop hl ex (sp), hl ; Callee - + ld b, a - ld c, h - + ld c, h + ld a, 191 cp b jr c, __PLOT_ERR ; jr is faster here (#1) - + __PLOT: ; __FASTCALL__ entry (b, c) = pixel coords (y, x) ld (COORDS), bc ; Saves current point ld a, 191 ; Max y coord @@ -681,7 +681,7 @@ __PLOT: ; __FASTCALL__ entry (b, c) = pixel coords (y, x) res 6, h ; Starts from 0 ld bc, (SCREEN_ADDR) add hl, bc ; Now current offset - + ld b, a inc b ld a, 0FEh @@ -689,7 +689,7 @@ __PLOT: ; __FASTCALL__ entry (b, c) = pixel coords (y, x) __PLOT_LOOP: rrca djnz __PLOT_LOOP - + ld b, a ld a, (P_FLAG) ld c, a @@ -697,18 +697,18 @@ __PLOT_LOOP: bit 0, c ; is it OVER 1 jr nz, __PLOT_OVER1 and b - + __PLOT_OVER1: bit 2, c ; is it inverse 1 jr nz, __PLOT_END - + xor b cpl - + LOCAL __PLOT_END __PLOT_END: ld (hl), a - + ;; gets ATTR position with offset given in SCREEN_ADDR ld a, h rrca @@ -719,36 +719,36 @@ __PLOT_END: ld h, a ld de, (SCREEN_ADDR) add hl, de ;; Final screen addr - + LOCAL PO_ATTR_2 PO_ATTR_2 EQU 0BE4h ; Another entry to PO_ATTR jp PO_ATTR_2 ; This will update attr accordingly. Beware, uses IY - + __PLOT_ERR: jp __OUT_OF_SCREEN_ERR ; Spent 3 bytes, but saves 3 T-States at (#1) - + PLOT_SUB EQU 22ECh - PIXEL_ADDR EQU 22ACh + PIXEL_ADDR EQU 22ACh COORDS EQU 5C7Dh ENDP #line 6 "circle.asm" - - + + ; Draws a circle at X, Y of radius R ; X, Y on the Stack, R in accumulator (Byte) - + PROC LOCAL __CIRCLE_ERROR LOCAL __CIRCLE_LOOP LOCAL __CIRCLE_NEXT - + __CIRCLE_ERROR: jp __OUT_OF_SCREEN_ERR ;; __CIRCLE_ERROR EQU __OUT_OF_SCREEN_ERR ;; __CIRCLE_ERROR: ;; ; Jumps here if out of screen ;; scf ; Always sets carry Flag - ;; + ;; ;; ld a, ERROR_OutOfScreen ;; ld (ERR_NR), a ;; ret @@ -758,95 +758,95 @@ CIRCLE: pop de ; D = Y ex (sp), hl ; __CALLEE__ convention ld e, h ; E = X - - - ld h, a ; H = R + + + ld h, a ; H = R add a, d sub 192 jr nc, __CIRCLE_ERROR - + ld a, d sub h jr c, __CIRCLE_ERROR - + ld a, e sub h jr c, __CIRCLE_ERROR - + ld a, h add a, e jr c, __CIRCLE_ERROR - - + + ; __FASTCALL__ Entry: D, E = Y, X point of the center ; A = Radious __CIRCLE: - push de + push de ld a, h exx pop de ; D'E' = x0, y0 ld h, a ; H' = r - + ld c, e ld a, h add a, d ld b, a call __CIRCLE_PLOT ; PLOT (x0, y0 + r) - + ld b, d ld a, h add a, e ld c, a call __CIRCLE_PLOT ; PLOT (x0 + r, y0) - + ld c, e ld a, d sub h ld b, a call __CIRCLE_PLOT ; PLOT (x0, y0 - r) - + ld b, d ld a, e sub h ld c, a call __CIRCLE_PLOT ; PLOT (x0 - r, y0) - + exx ld b, 0 ; B = x = 0 ld c, h ; C = y = Radius ld hl, 1 or a sbc hl, bc ; HL = f = 1 - radius - + ex de, hl ld hl, 0 or a sbc hl, bc ; HL = -radius add hl, hl ; HL = -2 * radius ex de, hl ; DE = -2 * radius = ddF_y, HL = f - + xor a ; A = ddF_x = 0 ex af, af' ; Saves it - + __CIRCLE_LOOP: ld a, b cp c ret nc ; Returns when x >= y - + bit 7, h ; HL >= 0? : if (f >= 0)... jp nz, __CIRCLE_NEXT - + dec c ; y-- inc de inc de ; ddF_y += 2 - + add hl, de ; f += ddF_y - + __CIRCLE_NEXT: inc b ; x++ ex af, af' add a, 2 ; 1 Cycle faster than inc a, inc a - + inc hl ; f++ push af add a, l @@ -856,11 +856,11 @@ __CIRCLE_NEXT: ld h, a pop af ex af, af' - - push bc + + push bc exx pop hl ; H'L' = Y, X - + ld a, d add a, h ld b, a ; B = y0 + y @@ -868,7 +868,7 @@ __CIRCLE_NEXT: add a, l ld c, a ; C = x0 + x call __CIRCLE_PLOT ; plot(x0 + x, y0 + y) - + ld a, d add a, h ld b, a ; B = y0 + y @@ -876,7 +876,7 @@ __CIRCLE_NEXT: sub l ld c, a ; C = x0 - x call __CIRCLE_PLOT ; plot(x0 - x, y0 + y) - + ld a, d sub h ld b, a ; B = y0 - y @@ -884,7 +884,7 @@ __CIRCLE_NEXT: add a, l ld c, a ; C = x0 + x call __CIRCLE_PLOT ; plot(x0 + x, y0 - y) - + ld a, d sub h ld b, a ; B = y0 - y @@ -892,79 +892,79 @@ __CIRCLE_NEXT: sub l ld c, a ; C = x0 - x call __CIRCLE_PLOT ; plot(x0 - x, y0 - y) - + ld a, d add a, l ld b, a ; B = y0 + x - ld a, e + ld a, e add a, h ld c, a ; C = x0 + y call __CIRCLE_PLOT ; plot(x0 + y, y0 + x) - + ld a, d add a, l ld b, a ; B = y0 + x - ld a, e + ld a, e sub h ld c, a ; C = x0 - y call __CIRCLE_PLOT ; plot(x0 - y, y0 + x) - + ld a, d sub l ld b, a ; B = y0 - x - ld a, e + ld a, e add a, h ld c, a ; C = x0 + y call __CIRCLE_PLOT ; plot(x0 + y, y0 - x) - + ld a, d sub l ld b, a ; B = y0 - x - ld a, e + ld a, e sub h ld c, a ; C = x0 + y call __CIRCLE_PLOT ; plot(x0 - y, y0 - x) - + exx jp __CIRCLE_LOOP - - - + + + __CIRCLE_PLOT: ; Plots a point of the circle, preserving HL and DE push hl push de - call __PLOT + call __PLOT pop de pop hl ret - + ENDP #line 469 "fastcall0.bas" - + #line 1 "pause.asm" - + ; The PAUSE statement (Calling the ROM) - + __PAUSE: ld b, h ld c, l jp 1F3Dh ; PAUSE_1 #line 471 "fastcall0.bas" #line 1 "usr_str.asm" - + ; This function just returns the address of the UDG of the given str. ; If the str is EMPTY or not a letter, 0 is returned and ERR_NR set ; to "A: Invalid Argument" - + ; On entry HL points to the string ; and A register is non-zero if the string must be freed (TMP string) - - + + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -972,13 +972,13 @@ __PAUSE: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 10 "usr_str.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -986,25 +986,25 @@ __PAUSE: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1013,41 +1013,41 @@ __PAUSE: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1055,25 +1055,25 @@ __PAUSE: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1082,39 +1082,39 @@ __PAUSE: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -1122,56 +1122,56 @@ __PAUSE: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -1180,57 +1180,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -1239,47 +1239,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -1289,27 +1289,27 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 11 "usr_str.asm" - + USR_STR: ex af, af' ; Saves A flag - + ld a, h or l jr z, USR_ERROR ; a$ = NULL => Invalid Arg - + ld d, h ; Saves HL in DE, for ld e, l ; later usage - + ld c, (hl) inc hl ld a, (hl) or c jr z, USR_ERROR ; a$ = "" => Invalid Arg - + inc hl ld a, (hl) ; Only the 1st char is needed and 11011111b ; Convert it to UPPER CASE @@ -1321,31 +1321,31 @@ USR_STR: add hl, hl ; hl = A * 8 ld bc, (UDG) add hl, bc - + ;; Now checks if the string must be released ex af, af' ; Recovers A flag or a ret z ; return if not - + push hl ; saves result since __MEM_FREE changes HL ex de, hl ; Recovers original HL value call __MEM_FREE pop hl ret - + USR_ERROR: ex de, hl ; Recovers original HL value ex af, af' ; Recovers A flag or a call nz, __MEM_FREE - + ld a, ERROR_InvalidArg ld (ERR_NR), a ld hl, 0 ret - + #line 472 "fastcall0.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/for0.asm b/tests/functional/for0.asm index ce7e4c631..716f0b8c7 100644 --- a/tests/functional/for0.asm +++ b/tests/functional/for0.asm @@ -55,20 +55,20 @@ __LABEL5: DEFW 0001h DEFB 20h #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -76,36 +76,36 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 9 "cls.asm" - + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -118,29 +118,29 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 42 "for0.bas" #line 1 "lti8.asm" - + #line 1 "lei8.asm" - + __LEI8: ; Signed <= comparison for 8bit int ; A <= H (registers) PROC @@ -149,10 +149,10 @@ __LEI8: ; Signed <= comparison for 8bit int jr nz, __LTI inc a ret - + __LTI8: ; Test 8 bit values A < H sub h - + __LTI: ; Generic signed comparison jp po, checkParity xor 0x80 @@ -165,35 +165,35 @@ checkParity: #line 2 "lti8.asm" #line 43 "for0.bas" #line 1 "printi8.asm" - + #line 1 "printnum.asm" - + #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - - - + + + #line 1 "in_screen.asm" - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -201,12 +201,12 @@ checkParity: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -214,51 +214,51 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "in_screen.asm" - + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -267,17 +267,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -285,26 +285,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -318,45 +318,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -367,28 +367,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -396,28 +396,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -426,83 +426,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -511,32 +511,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -546,7 +546,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -554,20 +554,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -577,7 +577,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -588,19 +588,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -610,7 +610,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -621,19 +621,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -643,7 +643,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -656,22 +656,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -680,79 +680,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -761,75 +761,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -839,7 +839,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -851,16 +851,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -874,49 +874,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -927,17 +927,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -950,27 +950,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -978,10 +978,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -998,80 +998,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1088,8 +1088,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1113,17 +1113,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1134,7 +1134,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1144,21 +1144,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1177,9 +1177,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1204,26 +1204,26 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 2 "printnum.asm" - - + + __PRINTU_START: PROC - + LOCAL __PRINTU_CONT - + ld a, b or a jp nz, __PRINTU_CONT - + ld a, '0' jp __PRINT_DIGIT - - + + __PRINTU_CONT: pop af push bc @@ -1231,63 +1231,63 @@ __PRINTU_CONT: pop bc djnz __PRINTU_CONT ret - + ENDP - - + + __PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers ld a, '-' jp __PRINT_DIGIT - + __PRINT_DIGIT EQU __PRINTCHAR ; PRINTS the char in A register, and puts its attrs - - + + #line 2 "printi8.asm" #line 1 "div8.asm" - + ; -------------------------------- -__DIVU8: ; 8 bit unsigned integer division +__DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A pop hl ; -------------------------------- ex (sp), hl ; CALLEE - + __DIVU8_FAST: ; Does A / H ld l, h ld h, a ; At this point do H / L - + ld b, 8 xor a ; A = 0, Carry Flag = 0 - + __DIV8LOOP: - sla h - rla - cp l + sla h + rla + cp l jr c, __DIV8NOSUB - sub l - inc h - -__DIV8NOSUB: + sub l + inc h + +__DIV8NOSUB: djnz __DIV8LOOP - + ld l, a ; save remainder - ld a, h ; - - ret ; a = Quotient, - - + ld a, h ; + + ret ; a = Quotient, + + ; -------------------------------- __DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A pop hl ; -------------------------------- ex (sp), hl - + __DIVI8_FAST: ld e, a ; store operands for later ld c, h - + or a ; negative? jp p, __DIV8A neg ; Make it positive - + __DIV8A: ex af, af' ld a, h @@ -1295,91 +1295,91 @@ __DIV8A: jp p, __DIV8B neg ld h, a ; make it positive - + __DIV8B: ex af, af' - + call __DIVU8_FAST - + ld a, c xor l ; bit 7 of A = 1 if result is negative - + ld a, h ; Quotient - ret p ; return if positive - + ret p ; return if positive + neg ret - - + + __MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) pop hl ex (sp), hl ; CALLEE - + __MODU8_FAST: ; __FASTCALL__ entry call __DIVU8_FAST ld a, l ; Remainder - + ret ; a = Modulus - - + + __MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) pop hl ex (sp), hl ; CALLEE - + __MODI8_FAST: ; __FASTCALL__ entry call __DIVI8_FAST ld a, l ; remainder - + ret ; a = Modulus - + #line 3 "printi8.asm" - + __PRINTI8: ; Prints an 8 bits number in Accumulator (A) ; Converts 8 to 32 bits or a jp p, __PRINTU8 - + push af call __PRINT_MINUS pop af neg - + __PRINTU8: PROC - + LOCAL __PRINTU_LOOP - + ld b, 0 ; Counter - + __PRINTU_LOOP: or a jp z, __PRINTU_START - + push bc ld h, 10 call __DIVU8_FAST ; Divides by 10. D'E'H'L' contains modulo (L' since < 10) pop bc - + ld a, l or '0' ; Stores ASCII digit (must be print in reversed order) push af ld a, h inc b jp __PRINTU_LOOP ; Uses JP in loops - + ENDP - + #line 44 "for0.bas" #line 1 "printstr.asm" - - - - + + + + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1387,25 +1387,25 @@ __PRINTU_LOOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1414,41 +1414,41 @@ __PRINTU_LOOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1456,25 +1456,25 @@ __PRINTU_LOOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1483,39 +1483,39 @@ __PRINTU_LOOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -1523,56 +1523,56 @@ __PRINTU_LOOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -1581,57 +1581,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -1640,47 +1640,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -1690,51 +1690,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 5 "printstr.asm" - + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1743,11 +1743,11 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 45 "for0.bas" - + ZXBASIC_USER_DATA: _x: DEFB 00 diff --git a/tests/functional/fornext.asm b/tests/functional/fornext.asm index 071756e87..4e608e5a1 100644 --- a/tests/functional/fornext.asm +++ b/tests/functional/fornext.asm @@ -86,7 +86,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _i: DEFB 00 diff --git a/tests/functional/fornext2.asm b/tests/functional/fornext2.asm index 99b98db31..7f973bba3 100644 --- a/tests/functional/fornext2.asm +++ b/tests/functional/fornext2.asm @@ -50,7 +50,7 @@ _test__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: _x: DEFB 00 diff --git a/tests/functional/fornext3.asm b/tests/functional/fornext3.asm index f466e2302..a2c98fed0 100644 --- a/tests/functional/fornext3.asm +++ b/tests/functional/fornext3.asm @@ -41,7 +41,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _i: DEFB 00, 00 diff --git a/tests/functional/fporder.asm b/tests/functional/fporder.asm index 75f3dcb38..f9f35818f 100644 --- a/tests/functional/fporder.asm +++ b/tests/functional/fporder.asm @@ -43,40 +43,40 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "cos.asm" - + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -92,21 +92,21 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 2 "cos.asm" - + COS: ; Computes COS using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 20h ; COS defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 34 "fporder.bas" #line 1 "mulf.asm" - - - + + + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) ; All of them uses A EDCB registers as 1st paramter. @@ -115,26 +115,26 @@ COS: ; Computes COS using ROM FP-CALC ; ; Uses CALLEE convention ; ------------------------------------------------------------- - + __MULF: ; Multiplication call __FPSTACK_PUSH2 - + ; ------------- ROM MUL rst 28h - defb 04h ; + defb 04h ; defb 38h; ; END CALC - + jp __FPSTACK_POP - + #line 35 "fporder.bas" #line 1 "pushf.asm" - - - ; Routine to push Float pointed by HL + + + ; Routine to push Float pointed by HL ; Into the stack. Notice that the hl points to the last ; byte of the FP number. ; Uses H'L' B'C' and D'E' to preserve ABCDEHL registers - + __FP_PUSH_REV: push hl exx @@ -155,11 +155,11 @@ __FP_PUSH_REV: push bc ; Return Address exx ret - - + + #line 36 "fporder.bas" #line 1 "storef.asm" - + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -167,7 +167,7 @@ __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory pop hl ; HL <- IX add hl, de ; HL <- IX + HL pop de - + __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register ex af, af' ld a, (hl) @@ -175,7 +175,7 @@ __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address ld h, (hl) ld l, a ; HL = (HL) ex af, af' - + __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), a inc hl @@ -187,36 +187,36 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL inc hl ld (hl), b ret - + #line 37 "fporder.bas" #line 1 "subf.asm" - - - + + + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) - + ; All of them uses A EDCB registers as 1st paramter. ; For binary operators, the 2n operator must be pushed into the ; stack, in the order A DE BC. ; ; Uses CALLEE convention ; ------------------------------------------------------------- - - + + __SUBF: ; Subtraction call __FPSTACK_PUSH2 ; ENTERS B, A - + ; ------------- ROM SUB rst 28h defb 01h ; EXCHANGE defb 03h ; SUB defb 38h; ; END CALC - + jp __FPSTACK_POP - + #line 38 "fporder.bas" - + ZXBASIC_USER_DATA: _n: DEFB 81h diff --git a/tests/functional/funccall0.asm b/tests/functional/funccall0.asm index bb1fe8a00..790414435 100644 --- a/tests/functional/funccall0.asm +++ b/tests/functional/funccall0.asm @@ -47,7 +47,7 @@ _test__leave: ex (sp), hl exx ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/funccall1.asm b/tests/functional/funccall1.asm index 03195bd50..9c4ed0c5b 100644 --- a/tests/functional/funccall1.asm +++ b/tests/functional/funccall1.asm @@ -49,7 +49,7 @@ _test2__leave: ex (sp), hl exx ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/funccall2.asm b/tests/functional/funccall2.asm index ff087c942..fd97ec6f2 100644 --- a/tests/functional/funccall2.asm +++ b/tests/functional/funccall2.asm @@ -41,7 +41,7 @@ _test__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/funcnoparm.asm b/tests/functional/funcnoparm.asm index f302619ea..9cccc44b4 100644 --- a/tests/functional/funcnoparm.asm +++ b/tests/functional/funcnoparm.asm @@ -49,7 +49,7 @@ _xx__leave: ex (sp), hl exx ret - + ZXBASIC_USER_DATA: _c: DEFB 00, 00 diff --git a/tests/functional/gef16.asm b/tests/functional/gef16.asm index 47e878dc4..315f9bb0d 100644 --- a/tests/functional/gef16.asm +++ b/tests/functional/gef16.asm @@ -92,52 +92,52 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "lti32.asm" - - + + #line 1 "sub32.asm" - - ; SUB32 + + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) ; and returns result in DEHL. Carry an Z are set correctly - + __SUB32: exx pop bc ; saves return address in BC' exx - + or a ; clears carry flag ld b, h ; Operands come reversed => BC <- HL, HL = HL - BC ld c, l pop hl sbc hl, bc ex de, hl - + ld b, h ; High part (DE) now in HL. Repeat operation ld c, l pop hl sbc hl, bc ex de, hl ; DEHL now has de 32 bit result - + exx push bc ; puts return address back exx ret #line 3 "lti32.asm" - + __LTI32: ; Test 32 bit values in Top of the stack < HLDE PROC LOCAL checkParity exx pop de ; Preserves return address exx - + call __SUB32 - + exx push de ; Restores return address exx - + jp po, checkParity ld a, d xor 0x80 @@ -149,10 +149,10 @@ checkParity: ENDP #line 83 "gef16.bas" #line 1 "swap32.asm" - + ; Exchanges current DE HL with the ; ones in the stack - + __SWAP32: pop bc ; Return address ex (sp), hl @@ -165,9 +165,9 @@ __SWAP32: inc sp push bc ret - + #line 84 "gef16.bas" - + ZXBASIC_USER_DATA: _level: DEFB 00h diff --git a/tests/functional/gei32.asm b/tests/functional/gei32.asm index 613251151..2dc95f04d 100644 --- a/tests/functional/gei32.asm +++ b/tests/functional/gei32.asm @@ -107,52 +107,52 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "lti32.asm" - - + + #line 1 "sub32.asm" - - ; SUB32 + + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) ; and returns result in DEHL. Carry an Z are set correctly - + __SUB32: exx pop bc ; saves return address in BC' exx - + or a ; clears carry flag ld b, h ; Operands come reversed => BC <- HL, HL = HL - BC ld c, l pop hl sbc hl, bc ex de, hl - + ld b, h ; High part (DE) now in HL. Repeat operation ld c, l pop hl sbc hl, bc ex de, hl ; DEHL now has de 32 bit result - + exx push bc ; puts return address back exx ret #line 3 "lti32.asm" - + __LTI32: ; Test 32 bit values in Top of the stack < HLDE PROC LOCAL checkParity exx pop de ; Preserves return address exx - + call __SUB32 - + exx push de ; Restores return address exx - + jp po, checkParity ld a, d xor 0x80 @@ -164,10 +164,10 @@ checkParity: ENDP #line 98 "gei32.bas" #line 1 "swap32.asm" - + ; Exchanges current DE HL with the ; ones in the stack - + __SWAP32: pop bc ; Return address ex (sp), hl @@ -180,9 +180,9 @@ __SWAP32: inc sp push bc ret - + #line 99 "gei32.bas" - + ZXBASIC_USER_DATA: _level: DEFB 00h diff --git a/tests/functional/gei8.asm b/tests/functional/gei8.asm index 50f405ca2..7813c9541 100644 --- a/tests/functional/gei8.asm +++ b/tests/functional/gei8.asm @@ -35,7 +35,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "lei8.asm" - + __LEI8: ; Signed <= comparison for 8bit int ; A <= H (registers) PROC @@ -44,10 +44,10 @@ __LEI8: ; Signed <= comparison for 8bit int jr nz, __LTI inc a ret - + __LTI8: ; Test 8 bit values A < H sub h - + __LTI: ; Generic signed comparison jp po, checkParity xor 0x80 @@ -58,7 +58,7 @@ checkParity: ret ENDP #line 26 "gei8.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/geu32.asm b/tests/functional/geu32.asm index 02d3214b2..41302f58d 100644 --- a/tests/functional/geu32.asm +++ b/tests/functional/geu32.asm @@ -107,40 +107,40 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sub32.asm" - - ; SUB32 + + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) ; and returns result in DEHL. Carry an Z are set correctly - + __SUB32: exx pop bc ; saves return address in BC' exx - + or a ; clears carry flag ld b, h ; Operands come reversed => BC <- HL, HL = HL - BC ld c, l pop hl sbc hl, bc ex de, hl - + ld b, h ; High part (DE) now in HL. Repeat operation ld c, l pop hl sbc hl, bc ex de, hl ; DEHL now has de 32 bit result - + exx push bc ; puts return address back exx ret #line 98 "geu32.bas" #line 1 "swap32.asm" - + ; Exchanges current DE HL with the ; ones in the stack - + __SWAP32: pop bc ; Return address ex (sp), hl @@ -153,9 +153,9 @@ __SWAP32: inc sp push bc ret - + #line 99 "geu32.bas" - + ZXBASIC_USER_DATA: _level: DEFB 00h diff --git a/tests/functional/gtf16.asm b/tests/functional/gtf16.asm index 53c88ffef..280761f21 100644 --- a/tests/functional/gtf16.asm +++ b/tests/functional/gtf16.asm @@ -92,52 +92,52 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "lei32.asm" - - + + #line 1 "sub32.asm" - - ; SUB32 + + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) ; and returns result in DEHL. Carry an Z are set correctly - + __SUB32: exx pop bc ; saves return address in BC' exx - + or a ; clears carry flag ld b, h ; Operands come reversed => BC <- HL, HL = HL - BC ld c, l pop hl sbc hl, bc ex de, hl - + ld b, h ; High part (DE) now in HL. Repeat operation ld c, l pop hl sbc hl, bc ex de, hl ; DEHL now has de 32 bit result - + exx push bc ; puts return address back exx ret #line 3 "lei32.asm" - + __LEI32: ; Test 32 bit values Top of the stack <= HL,DE PROC LOCAL checkParity exx pop de ; Preserves return address exx - + call __SUB32 - + exx push de ; Puts return address back exx - + ex af, af' ld a, h or l @@ -145,7 +145,7 @@ __LEI32: ; Test 32 bit values Top of the stack <= HL,DE or d ld a, 1 ret z - + ex af, af' jp po, checkParity ld a, d @@ -158,10 +158,10 @@ checkParity: ENDP #line 83 "gtf16.bas" #line 1 "swap32.asm" - + ; Exchanges current DE HL with the ; ones in the stack - + __SWAP32: pop bc ; Return address ex (sp), hl @@ -174,9 +174,9 @@ __SWAP32: inc sp push bc ret - + #line 84 "gtf16.bas" - + ZXBASIC_USER_DATA: _level: DEFB 00h diff --git a/tests/functional/gti32.asm b/tests/functional/gti32.asm index c81ba6b93..69642c59d 100644 --- a/tests/functional/gti32.asm +++ b/tests/functional/gti32.asm @@ -107,52 +107,52 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "lei32.asm" - - + + #line 1 "sub32.asm" - - ; SUB32 + + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) ; and returns result in DEHL. Carry an Z are set correctly - + __SUB32: exx pop bc ; saves return address in BC' exx - + or a ; clears carry flag ld b, h ; Operands come reversed => BC <- HL, HL = HL - BC ld c, l pop hl sbc hl, bc ex de, hl - + ld b, h ; High part (DE) now in HL. Repeat operation ld c, l pop hl sbc hl, bc ex de, hl ; DEHL now has de 32 bit result - + exx push bc ; puts return address back exx ret #line 3 "lei32.asm" - + __LEI32: ; Test 32 bit values Top of the stack <= HL,DE PROC LOCAL checkParity exx pop de ; Preserves return address exx - + call __SUB32 - + exx push de ; Puts return address back exx - + ex af, af' ld a, h or l @@ -160,7 +160,7 @@ __LEI32: ; Test 32 bit values Top of the stack <= HL,DE or d ld a, 1 ret z - + ex af, af' jp po, checkParity ld a, d @@ -173,10 +173,10 @@ checkParity: ENDP #line 98 "gti32.bas" #line 1 "swap32.asm" - + ; Exchanges current DE HL with the ; ones in the stack - + __SWAP32: pop bc ; Return address ex (sp), hl @@ -189,9 +189,9 @@ __SWAP32: inc sp push bc ret - + #line 99 "gti32.bas" - + ZXBASIC_USER_DATA: _level: DEFB 00h diff --git a/tests/functional/gti8.asm b/tests/functional/gti8.asm index 27cc14d43..926b7ccf5 100644 --- a/tests/functional/gti8.asm +++ b/tests/functional/gti8.asm @@ -36,9 +36,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "lti8.asm" - + #line 1 "lei8.asm" - + __LEI8: ; Signed <= comparison for 8bit int ; A <= H (registers) PROC @@ -47,10 +47,10 @@ __LEI8: ; Signed <= comparison for 8bit int jr nz, __LTI inc a ret - + __LTI8: ; Test 8 bit values A < H sub h - + __LTI: ; Generic signed comparison jp po, checkParity xor 0x80 @@ -62,7 +62,7 @@ checkParity: ENDP #line 2 "lti8.asm" #line 27 "gti8.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/gtu32.asm b/tests/functional/gtu32.asm index 3ce19ea08..644257340 100644 --- a/tests/functional/gtu32.asm +++ b/tests/functional/gtu32.asm @@ -127,10 +127,10 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "swap32.asm" - + ; Exchanges current DE HL with the ; ones in the stack - + __SWAP32: pop bc ; Return address ex (sp), hl @@ -143,9 +143,9 @@ __SWAP32: inc sp push bc ret - + #line 118 "gtu32.bas" - + ZXBASIC_USER_DATA: _level: DEFB 00h diff --git a/tests/functional/gtu8.asm b/tests/functional/gtu8.asm index cfb34446c..e27cc2be7 100644 --- a/tests/functional/gtu8.asm +++ b/tests/functional/gtu8.asm @@ -34,7 +34,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/idco.asm b/tests/functional/idco.asm index c4357ed5b..988233081 100644 --- a/tests/functional/idco.asm +++ b/tests/functional/idco.asm @@ -37,7 +37,7 @@ _p__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/ifelse0.asm b/tests/functional/ifelse0.asm index ec7fef5c3..9e4b187ec 100644 --- a/tests/functional/ifelse0.asm +++ b/tests/functional/ifelse0.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/ifelse1.asm b/tests/functional/ifelse1.asm index 12147cacd..f4b2ea7e2 100644 --- a/tests/functional/ifelse1.asm +++ b/tests/functional/ifelse1.asm @@ -57,17 +57,17 @@ __LABEL2: DEFB 6Eh DEFB 21h #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -75,46 +75,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -127,43 +127,43 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -171,12 +171,12 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -184,51 +184,51 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "in_screen.asm" - + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -237,17 +237,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -255,26 +255,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -288,45 +288,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -337,28 +337,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -366,28 +366,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -396,83 +396,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -481,32 +481,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -516,7 +516,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -524,20 +524,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -547,7 +547,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -558,19 +558,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -580,7 +580,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -591,19 +591,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -613,7 +613,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -626,22 +626,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -650,79 +650,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -731,75 +731,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -809,7 +809,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -821,16 +821,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -844,49 +844,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -897,17 +897,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -920,27 +920,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -948,10 +948,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -968,80 +968,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1058,8 +1058,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1083,17 +1083,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1104,7 +1104,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1114,21 +1114,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1147,9 +1147,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1174,21 +1174,21 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 44 "ifelse1.bas" #line 1 "printstr.asm" - - - - + + + + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1196,25 +1196,25 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1223,41 +1223,41 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1265,25 +1265,25 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1292,39 +1292,39 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -1332,56 +1332,56 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -1390,57 +1390,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -1449,47 +1449,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -1499,51 +1499,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 5 "printstr.asm" - + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1552,11 +1552,11 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 45 "ifelse1.bas" - + ZXBASIC_USER_DATA: _a: DEFB 02h diff --git a/tests/functional/ifthen.asm b/tests/functional/ifthen.asm index dde663935..47d00eb57 100644 --- a/tests/functional/ifthen.asm +++ b/tests/functional/ifthen.asm @@ -49,9 +49,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "lti8.asm" - + #line 1 "lei8.asm" - + __LEI8: ; Signed <= comparison for 8bit int ; A <= H (registers) PROC @@ -60,10 +60,10 @@ __LEI8: ; Signed <= comparison for 8bit int jr nz, __LTI inc a ret - + __LTI8: ; Test 8 bit values A < H sub h - + __LTI: ; Generic signed comparison jp po, checkParity xor 0x80 @@ -75,7 +75,7 @@ checkParity: ENDP #line 2 "lti8.asm" #line 40 "ifthen.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/ifthenelse.asm b/tests/functional/ifthenelse.asm index f3268e58e..59c4d7294 100644 --- a/tests/functional/ifthenelse.asm +++ b/tests/functional/ifthenelse.asm @@ -57,9 +57,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "lti8.asm" - + #line 1 "lei8.asm" - + __LEI8: ; Signed <= comparison for 8bit int ; A <= H (registers) PROC @@ -68,10 +68,10 @@ __LEI8: ; Signed <= comparison for 8bit int jr nz, __LTI inc a ret - + __LTI8: ; Test 8 bit values A < H sub h - + __LTI: ; Generic signed comparison jp po, checkParity xor 0x80 @@ -83,7 +83,7 @@ checkParity: ENDP #line 2 "lti8.asm" #line 48 "ifthenelse.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/ifthenelseif.asm b/tests/functional/ifthenelseif.asm index b8e3c1ec9..b9dde0908 100644 --- a/tests/functional/ifthenelseif.asm +++ b/tests/functional/ifthenelseif.asm @@ -126,9 +126,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "lti8.asm" - + #line 1 "lei8.asm" - + __LEI8: ; Signed <= comparison for 8bit int ; A <= H (registers) PROC @@ -137,10 +137,10 @@ __LEI8: ; Signed <= comparison for 8bit int jr nz, __LTI inc a ret - + __LTI8: ; Test 8 bit values A < H sub h - + __LTI: ; Generic signed comparison jp po, checkParity xor 0x80 @@ -152,7 +152,7 @@ checkParity: ENDP #line 2 "lti8.asm" #line 117 "ifthenelseif.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/in0.asm b/tests/functional/in0.asm index 5da1dabeb..ffd8f5214 100644 --- a/tests/functional/in0.asm +++ b/tests/functional/in0.asm @@ -29,7 +29,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/inkey.asm b/tests/functional/inkey.asm index 376a7566b..0ba1eb83a 100644 --- a/tests/functional/inkey.asm +++ b/tests/functional/inkey.asm @@ -43,17 +43,17 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "inkey.asm" - + ; INKEY Function ; Returns a string allocated in dynamic memory ; containing the string. ; An empty string otherwise. - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -61,25 +61,25 @@ __CALL_BACK__: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -88,51 +88,51 @@ __CALL_BACK__: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -140,12 +140,12 @@ __CALL_BACK__: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -153,7 +153,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -161,10 +161,10 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -172,25 +172,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -199,39 +199,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -239,57 +239,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -301,27 +301,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -333,7 +333,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -341,15 +341,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -374,14 +374,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -389,50 +389,50 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 7 "inkey.asm" - + INKEY: - PROC + PROC LOCAL __EMPTY_INKEY LOCAL KEY_SCAN LOCAL KEY_TEST LOCAL KEY_CODE - - ld bc, 3 ; 1 char length string + + ld bc, 3 ; 1 char length string call __MEM_ALLOC - + ld a, h or l ret z ; Return if NULL (No memory) - + push hl ; Saves memory pointer - + call KEY_SCAN jp nz, __EMPTY_INKEY - + call KEY_TEST jp nc, __EMPTY_INKEY - + dec d ; D is expected to be FLAGS so set bit 3 $FF ; 'L' Mode so no keywords. ld e, a ; main key to A ; C is MODE 0 'KLC' from above still. call KEY_CODE ; routine K-DECODE pop hl - + ld (hl), 1 inc hl ld (hl), 0 @@ -441,7 +441,7 @@ INKEY: dec hl dec hl ; HL Points to string result ret - + __EMPTY_INKEY: pop hl xor a @@ -450,26 +450,26 @@ __EMPTY_INKEY: ld (hl), a dec hl ret - + KEY_SCAN EQU 028Eh KEY_TEST EQU 031Eh KEY_CODE EQU 0333h - + ENDP - + #line 30 "inkey.bas" #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -477,46 +477,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -529,67 +529,67 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - - - + + + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -598,17 +598,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -616,26 +616,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -649,45 +649,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -698,28 +698,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -727,28 +727,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -757,83 +757,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -842,32 +842,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -877,7 +877,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -885,20 +885,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -908,7 +908,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -919,19 +919,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -941,7 +941,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -952,19 +952,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -974,7 +974,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -987,22 +987,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -1011,79 +1011,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -1092,75 +1092,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -1170,7 +1170,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -1182,16 +1182,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1205,49 +1205,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1258,17 +1258,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1281,27 +1281,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1309,10 +1309,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1329,80 +1329,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1419,8 +1419,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1444,17 +1444,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1465,7 +1465,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1475,21 +1475,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1508,9 +1508,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1535,33 +1535,33 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 31 "inkey.bas" #line 1 "print_eol_attr.asm" - + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes - - - - + + + + PRINT_EOL_ATTR: call PRINT_EOL jp COPY_ATTR #line 32 "inkey.bas" #line 1 "printstr.asm" - - - - + + + + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1569,25 +1569,25 @@ PRINT_EOL_ATTR: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1596,38 +1596,38 @@ PRINT_EOL_ATTR: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -1636,57 +1636,57 @@ PRINT_EOL_ATTR: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -1695,47 +1695,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -1745,51 +1745,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 5 "printstr.asm" - + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1798,53 +1798,53 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 33 "inkey.bas" #line 1 "storestr2.asm" - + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication ; HL = address of string memory variable ; DE = address of 2n string. It just copies DE into (HL) ; freeing (HL) previously. - - - + + + __PISTORE_STR2: ; Indirect store temporary string at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR2: ld c, (hl) ; Dereferences HL inc hl ld h, (hl) ld l, c ; HL = *HL (real string variable address) - + __STORE_STR2: push hl ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = *HL (real string address) - + push de call __MEM_FREE pop de - + pop hl ld (hl), e inc hl ld (hl), d dec hl ; HL points to mem address variable. This might be useful in the future. - + ret - + #line 34 "inkey.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/inktemp.asm b/tests/functional/inktemp.asm index 11621705a..f810689ee 100644 --- a/tests/functional/inktemp.asm +++ b/tests/functional/inktemp.asm @@ -52,25 +52,25 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "circle.asm" - + ; Bresenham's like circle algorithm ; best known as Middle Point Circle drawing algorithm - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -78,12 +78,12 @@ __CALL_BACK__: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -91,7 +91,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -99,22 +99,22 @@ __STOP: ret #line 5 "circle.asm" #line 1 "plot.asm" - + ; MIXED __FASTCAL__ / __CALLE__ PLOT Function ; Plots a point into the screen calling the ZX ROM PLOT routine - + ; Y in A (accumulator) ; X in top of the stack - - + + #line 1 "in_screen.asm" - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -122,75 +122,75 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 2 "in_screen.asm" - - + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 9 "plot.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -203,48 +203,48 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 10 "plot.asm" - + PLOT: PROC - + LOCAL PLOT_SUB LOCAL PIXEL_ADDR LOCAL COORDS LOCAL __PLOT_ERR LOCAL P_FLAG LOCAL __PLOT_OVER1 - + P_FLAG EQU 23697 - + pop hl ex (sp), hl ; Callee - + ld b, a - ld c, h - + ld c, h + ld a, 191 cp b jr c, __PLOT_ERR ; jr is faster here (#1) - + __PLOT: ; __FASTCALL__ entry (b, c) = pixel coords (y, x) ld (COORDS), bc ; Saves current point ld a, 191 ; Max y coord @@ -252,7 +252,7 @@ __PLOT: ; __FASTCALL__ entry (b, c) = pixel coords (y, x) res 6, h ; Starts from 0 ld bc, (SCREEN_ADDR) add hl, bc ; Now current offset - + ld b, a inc b ld a, 0FEh @@ -260,7 +260,7 @@ __PLOT: ; __FASTCALL__ entry (b, c) = pixel coords (y, x) __PLOT_LOOP: rrca djnz __PLOT_LOOP - + ld b, a ld a, (P_FLAG) ld c, a @@ -268,18 +268,18 @@ __PLOT_LOOP: bit 0, c ; is it OVER 1 jr nz, __PLOT_OVER1 and b - + __PLOT_OVER1: bit 2, c ; is it inverse 1 jr nz, __PLOT_END - + xor b cpl - + LOCAL __PLOT_END __PLOT_END: ld (hl), a - + ;; gets ATTR position with offset given in SCREEN_ADDR ld a, h rrca @@ -290,36 +290,36 @@ __PLOT_END: ld h, a ld de, (SCREEN_ADDR) add hl, de ;; Final screen addr - + LOCAL PO_ATTR_2 PO_ATTR_2 EQU 0BE4h ; Another entry to PO_ATTR jp PO_ATTR_2 ; This will update attr accordingly. Beware, uses IY - + __PLOT_ERR: jp __OUT_OF_SCREEN_ERR ; Spent 3 bytes, but saves 3 T-States at (#1) - + PLOT_SUB EQU 22ECh - PIXEL_ADDR EQU 22ACh + PIXEL_ADDR EQU 22ACh COORDS EQU 5C7Dh ENDP #line 6 "circle.asm" - - + + ; Draws a circle at X, Y of radius R ; X, Y on the Stack, R in accumulator (Byte) - + PROC LOCAL __CIRCLE_ERROR LOCAL __CIRCLE_LOOP LOCAL __CIRCLE_NEXT - + __CIRCLE_ERROR: jp __OUT_OF_SCREEN_ERR ;; __CIRCLE_ERROR EQU __OUT_OF_SCREEN_ERR ;; __CIRCLE_ERROR: ;; ; Jumps here if out of screen ;; scf ; Always sets carry Flag - ;; + ;; ;; ld a, ERROR_OutOfScreen ;; ld (ERR_NR), a ;; ret @@ -329,95 +329,95 @@ CIRCLE: pop de ; D = Y ex (sp), hl ; __CALLEE__ convention ld e, h ; E = X - - - ld h, a ; H = R + + + ld h, a ; H = R add a, d sub 192 jr nc, __CIRCLE_ERROR - + ld a, d sub h jr c, __CIRCLE_ERROR - + ld a, e sub h jr c, __CIRCLE_ERROR - + ld a, h add a, e jr c, __CIRCLE_ERROR - - + + ; __FASTCALL__ Entry: D, E = Y, X point of the center ; A = Radious __CIRCLE: - push de + push de ld a, h exx pop de ; D'E' = x0, y0 ld h, a ; H' = r - + ld c, e ld a, h add a, d ld b, a call __CIRCLE_PLOT ; PLOT (x0, y0 + r) - + ld b, d ld a, h add a, e ld c, a call __CIRCLE_PLOT ; PLOT (x0 + r, y0) - + ld c, e ld a, d sub h ld b, a call __CIRCLE_PLOT ; PLOT (x0, y0 - r) - + ld b, d ld a, e sub h ld c, a call __CIRCLE_PLOT ; PLOT (x0 - r, y0) - + exx ld b, 0 ; B = x = 0 ld c, h ; C = y = Radius ld hl, 1 or a sbc hl, bc ; HL = f = 1 - radius - + ex de, hl ld hl, 0 or a sbc hl, bc ; HL = -radius add hl, hl ; HL = -2 * radius ex de, hl ; DE = -2 * radius = ddF_y, HL = f - + xor a ; A = ddF_x = 0 ex af, af' ; Saves it - + __CIRCLE_LOOP: ld a, b cp c ret nc ; Returns when x >= y - + bit 7, h ; HL >= 0? : if (f >= 0)... jp nz, __CIRCLE_NEXT - + dec c ; y-- inc de inc de ; ddF_y += 2 - + add hl, de ; f += ddF_y - + __CIRCLE_NEXT: inc b ; x++ ex af, af' add a, 2 ; 1 Cycle faster than inc a, inc a - + inc hl ; f++ push af add a, l @@ -427,11 +427,11 @@ __CIRCLE_NEXT: ld h, a pop af ex af, af' - - push bc + + push bc exx pop hl ; H'L' = Y, X - + ld a, d add a, h ld b, a ; B = y0 + y @@ -439,7 +439,7 @@ __CIRCLE_NEXT: add a, l ld c, a ; C = x0 + x call __CIRCLE_PLOT ; plot(x0 + x, y0 + y) - + ld a, d add a, h ld b, a ; B = y0 + y @@ -447,7 +447,7 @@ __CIRCLE_NEXT: sub l ld c, a ; C = x0 - x call __CIRCLE_PLOT ; plot(x0 - x, y0 + y) - + ld a, d sub h ld b, a ; B = y0 - y @@ -455,7 +455,7 @@ __CIRCLE_NEXT: add a, l ld c, a ; C = x0 + x call __CIRCLE_PLOT ; plot(x0 + x, y0 - y) - + ld a, d sub h ld b, a ; B = y0 - y @@ -463,63 +463,63 @@ __CIRCLE_NEXT: sub l ld c, a ; C = x0 - x call __CIRCLE_PLOT ; plot(x0 - x, y0 - y) - + ld a, d add a, l ld b, a ; B = y0 + x - ld a, e + ld a, e add a, h ld c, a ; C = x0 + y call __CIRCLE_PLOT ; plot(x0 + y, y0 + x) - + ld a, d add a, l ld b, a ; B = y0 + x - ld a, e + ld a, e sub h ld c, a ; C = x0 - y call __CIRCLE_PLOT ; plot(x0 - y, y0 + x) - + ld a, d sub l ld b, a ; B = y0 - x - ld a, e + ld a, e add a, h ld c, a ; C = x0 + y call __CIRCLE_PLOT ; plot(x0 + y, y0 - x) - + ld a, d sub l ld b, a ; B = y0 - x - ld a, e + ld a, e sub h ld c, a ; C = x0 + y call __CIRCLE_PLOT ; plot(x0 - y, y0 - x) - + exx jp __CIRCLE_LOOP - - - + + + __CIRCLE_PLOT: ; Plots a point of the circle, preserving HL and DE push hl push de - call __PLOT + call __PLOT pop de pop hl ret - + ENDP #line 43 "inktemp.bas" #line 1 "copy_attr.asm" - + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -527,35 +527,35 @@ __CIRCLE_PLOT: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 6 "copy_attr.asm" - + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - + #line 63 "/src/zxb/trunk/library-asm/copy_attr.asm" ret #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -564,186 +564,186 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 44 "inktemp.bas" #line 1 "draw.asm" - + ; DRAW using bresenhams algorithm and screen positioning ; Copyleft (k) 2010 by J. Rodriguez (a.k.a. Boriel) http://www.boriel.com ; vim:ts=4:et:sw=4: - + ; Y parameter in A ; X parameter in high byte on top of the stack - - - - - - + + + + + + #line 1 "PixelDown.asm" - - ; - ; PixelDown - ; Alvin Albrecht 2002 - ; - - ; Pixel Down - ; - ; Adjusts screen address HL to move one pixel down in the display. - ; (0,0) is located at the top left corner of the screen. - ; -; enter: HL = valid screen address -; exit : Carry = moved off screen - ; Carry'= moved off current cell (needs ATTR update) - ; HL = moves one pixel down -; used : AF, HL - -SP.PixelDown: - inc h - ld a,h - and $07 - ret nz - ex af, af' ; Sets carry on F' - scf ; which flags ATTR must be updated - ex af, af' - ld a,h - sub $08 - ld h,a - ld a,l - add a,$20 - ld l,a - ret nc - ld a,h - add a,$08 - ld h,a - ;IF DISP_HIRES - ; and $18 - ; cp $18 - ;ELSE - cp $58 - ;ENDIF - ccf - ret + + ; + ; PixelDown + ; Alvin Albrecht 2002 + ; + + ; Pixel Down + ; + ; Adjusts screen address HL to move one pixel down in the display. + ; (0,0) is located at the top left corner of the screen. + ; +; enter: HL = valid screen address +; exit : Carry = moved off screen + ; Carry'= moved off current cell (needs ATTR update) + ; HL = moves one pixel down +; used : AF, HL + +SP.PixelDown: + inc h + ld a,h + and $07 + ret nz + ex af, af' ; Sets carry on F' + scf ; which flags ATTR must be updated + ex af, af' + ld a,h + sub $08 + ld h,a + ld a,l + add a,$20 + ld l,a + ret nc + ld a,h + add a,$08 + ld h,a + ;IF DISP_HIRES + ; and $18 + ; cp $18 + ;ELSE + cp $58 + ;ENDIF + ccf + ret #line 14 "draw.asm" #line 1 "PixelUp.asm" - - ; - ; PixelUp - ; Alvin Albrecht 2002 - ; - - ; Pixel Up - ; - ; Adjusts screen address HL to move one pixel up in the display. - ; (0,0) is located at the top left corner of the screen. - ; -; enter: HL = valid screen address -; exit : Carry = moved off screen - ; HL = moves one pixel up -; used : AF, HL - -SP.PixelUp: - ld a,h - dec h - and $07 - ret nz - ex af, af' - scf - ex af, af' - ld a,$08 - add a,h - ld h,a - ld a,l - sub $20 - ld l,a - ret nc - ld a,h - sub $08 - ld h,a - ;IF DISP_HIRES - ; and $18 - ; cp $18 - ; ccf - ;ELSE - cp $40 - ;ENDIF - ret + + ; + ; PixelUp + ; Alvin Albrecht 2002 + ; + + ; Pixel Up + ; + ; Adjusts screen address HL to move one pixel up in the display. + ; (0,0) is located at the top left corner of the screen. + ; +; enter: HL = valid screen address +; exit : Carry = moved off screen + ; HL = moves one pixel up +; used : AF, HL + +SP.PixelUp: + ld a,h + dec h + and $07 + ret nz + ex af, af' + scf + ex af, af' + ld a,$08 + add a,h + ld h,a + ld a,l + sub $20 + ld l,a + ret nc + ld a,h + sub $08 + ld h,a + ;IF DISP_HIRES + ; and $18 + ; cp $18 + ; ccf + ;ELSE + cp $40 + ;ENDIF + ret #line 15 "draw.asm" #line 1 "PixelLeft.asm" - - ; - ; PixelLeft - ; Jose Rodriguez 2012 - ; - - ; PixelLeft - ; - ; Adjusts screen address HL and Pixel bit A to move one pixel to the left - ; on the display. Start of line set Carry (Out of Screen) - ; -; enter: HL = valid screen address - ; A = Bit Set -; exit : Carry = moved off screen - ; Carry' Set if moved off current ATTR CELL - ; HL = moves one character left, if needed - ; A = Bit Set with new pixel pos. -; used : AF, HL - - -SP.PixelLeft: - rlca ; Sets new pixel bit 1 to the right - ret nc - ex af, af' ; Signal in C' we've moved off current ATTR cell - ld a,l - dec a - ld l,a - cp 32 ; Carry if in screen - ccf - ld a, 1 - ret - + + ; + ; PixelLeft + ; Jose Rodriguez 2012 + ; + + ; PixelLeft + ; + ; Adjusts screen address HL and Pixel bit A to move one pixel to the left + ; on the display. Start of line set Carry (Out of Screen) + ; +; enter: HL = valid screen address + ; A = Bit Set +; exit : Carry = moved off screen + ; Carry' Set if moved off current ATTR CELL + ; HL = moves one character left, if needed + ; A = Bit Set with new pixel pos. +; used : AF, HL + + +SP.PixelLeft: + rlca ; Sets new pixel bit 1 to the right + ret nc + ex af, af' ; Signal in C' we've moved off current ATTR cell + ld a,l + dec a + ld l,a + cp 32 ; Carry if in screen + ccf + ld a, 1 + ret + #line 16 "draw.asm" #line 1 "PixelRight.asm" - - ; - ; PixelRight - ; Jose Rodriguez 2012 - ; - - - ; PixelRight - ; - ; Adjusts screen address HL and Pixel bit A to move one pixel to the left - ; on the display. Start of line set Carry (Out of Screen) - ; -; enter: HL = valid screen address - ; A = Bit Set -; exit : Carry = moved off screen - ; Carry' Set if moved off current ATTR CELL - ; HL = moves one character left, if needed - ; A = Bit Set with new pixel pos. -; used : AF, HL - - -SP.PixelRight: - rrca ; Sets new pixel bit 1 to the right - ret nc - ex af, af' ; Signal in C' we've moved off current ATTR cell - ld a, l - inc a - ld l, a - cp 32 ; Carry if IN screen - ccf - ld a, 80h - ret - + + ; + ; PixelRight + ; Jose Rodriguez 2012 + ; + + + ; PixelRight + ; + ; Adjusts screen address HL and Pixel bit A to move one pixel to the left + ; on the display. Start of line set Carry (Out of Screen) + ; +; enter: HL = valid screen address + ; A = Bit Set +; exit : Carry = moved off screen + ; Carry' Set if moved off current ATTR CELL + ; HL = moves one character left, if needed + ; A = Bit Set with new pixel pos. +; used : AF, HL + + +SP.PixelRight: + rrca ; Sets new pixel bit 1 to the right + ret nc + ex af, af' ; Signal in C' we've moved off current ATTR cell + ld a, l + inc a + ld l, a + cp 32 ; Carry if IN screen + ccf + ld a, 80h + ret + #line 17 "draw.asm" - + ;; DRAW PROCEDURE - PROC - + PROC + LOCAL __DRAW1 LOCAL __DRAW2 LOCAL __DRAW3 @@ -755,22 +755,22 @@ SP.PixelRight: LOCAL __INCX, __INCY, __DECX, __DECY LOCAL P_FLAG P_FLAG EQU 23697 - + __DRAW_ERROR: jp __OUT_OF_SCREEN_ERR - + DRAW: ;; ENTRY POINT - + LOCAL PIXEL_ADDR LOCAL COORDS LOCAL __DRAW_SETUP1, __DRAW_START, __PLOTOVER, __PLOTINVERSE - + ex de, hl ; DE = Y OFFSET pop hl ; return addr ex (sp), hl ; CALLEE => HL = X OFFSET ld bc, (COORDS) - + ld a, c add a, l ld l, a @@ -778,26 +778,26 @@ DRAW: adc a, 0 ; HL = HL + C ld h, a jr nz, __DRAW_ERROR ; if a <> 0 => Out of Screen - + ld a, b add a, e - ld e, a + ld e, a ld a, d adc a, 0 ; DE = DE + B ld d, a jr nz, __DRAW_ERROR ; if a <> 0 => Out of Screen - + ld a, 191 sub e jr c, __DRAW_ERROR ; Out of screen - + ld h, e ; now H,L = y2, x2 - + __DRAW: ; __FASTCALL__ Entry. Plots from (COORDS) to coord H, L push hl ex de, hl ; D,E = y2, x2; - + ld a, (P_FLAG) ld c, a bit 2, a ; Test for INVERSE1 @@ -806,7 +806,7 @@ __DRAW: ld (__PLOTINVERSE), a ld a, 0A6h ; and (hl) jp __DRAW_START - + __DRAW_SETUP1: xor a ; nop ld (__PLOTINVERSE), a @@ -814,7 +814,7 @@ __DRAW_SETUP1: bit 0, c ; Test for OVER jr z, __DRAW_START ld a, 0AEh ; xor (hl) - + __DRAW_START: ld (__PLOTOVER), a ; "Pokes" last operation exx @@ -824,7 +824,7 @@ __DRAW_START: LOCAL __PIXEL_ADDR __PIXEL_ADDR EQU 22ACh call __PIXEL_ADDR - + ;; Now gets pixel mask in A register ld b, a inc b @@ -834,7 +834,7 @@ __DRAW_START: __PIXEL_MASK: rra djnz __PIXEL_MASK - + ld b, d ; Restores B' from D' pop de ; D'E' = y2, x2 exx ; At this point: D'E' = y2,x2 coords @@ -842,147 +842,147 @@ __PIXEL_MASK: ex af, af' ; Saves A reg for later ; A' = Pixel mask ; H'L' = Screen Address of pixel - + ld bc, (COORDS) ; B,C = y1, x1 - - ld a, e + + ld a, e sub c ; dx = X2 - X1 ld c, a ; Saves dx in c - + ld a, 0Ch ; INC C opcode ld hl, __INCX ; xi = 1 jr nc, __DRAW1 - + ld a, c neg ; dx = X1 - X2 ld c, a ld a, 0Dh ; DEC C opcode ld hl, __DECX ; xi = -1 - + __DRAW1: ld (DX1), a ld (DX1 + 2), hl ; Updates DX1 call address ld (DX2), a ld (DX2 + 2), hl ; Updates DX2 call address - + ld a, d sub b ; dy = Y2 - Y1 ld b, a ; Saves dy in b - + ld a, 4 ; INC B opcode ld hl, __INCY ; y1 = 1 jr nc, __DRAW2 - + ld a, b neg ld b, a ; dy = Y2 - Y1 ld a, 5 ; DEC B opcode ld hl, __DECY ; y1 = -1 - + __DRAW2: ld (DY1), a ld (DY1 + 2), hl ; Updates DX1 call address ld (DY2), a ld (DY2 + 2), hl ; Updates DX2 call address - + ld a, b sub c ; dy - dx jr c, __DRAW_DX_GT_DY ; DX > DY - + ; At this point DY >= DX ; -------------------------- ; HL = error = dY / 2 ld h, 0 ld l, b srl l - + ; DE = -dX xor a sub c ld e, a sbc a, a ld d, a - + ; BC = DY ld c, b ld b, h - + exx scf ; Sets Carry to signal update ATTR ex af, af' ; Brings back pixel mask ld e, a ; Saves it in free E register jp __DRAW4_LOOP - + __DRAW3: ; While c != e => while y != y2 exx add hl, de ; error -= dX bit 7, h ; exx ; recover coordinates - jr z, __DRAW4 ; if error < 0 - + jr z, __DRAW4 ; if error < 0 + exx - add hl, bc ; error += dY + add hl, bc ; error += dY exx - + ld a, e DX1: ; x += xi inc c call __INCX ; This address will be dynamically updated ld e, a - + __DRAW4: - + DY1: ; y += yi inc b call __INCY ; This address will be dyncamically updated ld a, e ; Restores A reg. call __FASTPLOT - + __DRAW4_LOOP: ld a, b cp d jp nz, __DRAW3 ld (COORDS), bc - ret - + ret + __DRAW_DX_GT_DY: ; DX > DY ; -------------------------- ; HL = error = dX / 2 ld h, 0 - ld l, c + ld l, c srl l ; HL = error = DX / 2 - + ; DE = -dY xor a sub b ld e, a sbc a, a ld d, a - + ; BC = dX ld b, h - + exx ld d, e scf ; Sets Carry to signal update ATTR ex af, af' ; Brings back pixel mask ld e, a ; Saves it in free E register jp __DRAW6_LOOP - + __DRAW5: ; While loop exx add hl, de ; error -= dY bit 7, h ; if (error < 0) exx ; Restore coords - jr z, __DRAW6 ; + jr z, __DRAW6 ; exx add hl, bc ; error += dX - exx - + exx + DY2: ; y += yi inc b call __INCY ; This address will be dynamically updated - + __DRAW6: ld a, e DX2: ; x += xi @@ -990,40 +990,40 @@ DX2: ; x += xi call __INCX ; This address will be dynamically updated ld e, a call __FASTPLOT - + __DRAW6_LOOP: ld a, c ; Current X coord cp d jp nz, __DRAW5 ld (COORDS), bc ret - - PIXEL_ADDR EQU 22ACh + + PIXEL_ADDR EQU 22ACh COORDS EQU 5C7Dh - + __DRAW_END: exx ret - + ;; Given a A mask and an HL screen position ;; return the next left position ;; Also updates BC coords __DECX EQU SP.PixelLeft - + ;; Like the above, but to the RIGHT ;; Also updates BC coords __INCX EQU SP.PixelRight - + ;; Given an HL screen position, calculates ;; the above position ;; Also updates BC coords __INCY EQU SP.PixelUp - + ;; Given an HL screen position, calculates ;; the above position ;; Also updates BC coords __DECY EQU SP.PixelDown - + ;; Puts the A register MASK in (HL) __FASTPLOT: __PLOTINVERSE: @@ -1031,12 +1031,12 @@ __PLOTINVERSE: __PLOTOVER: or (hl) ; Replace with XOR (hl) if OVER 1 AND INVERSE 0 ; Replace with AND (hl) if INVERSE 1 - + ld (hl), a ex af, af' ; Recovers flag. If Carry set => update ATTR ld a, e ; Recovers A reg ret nc - + push hl push de ;; gets ATTR position with offset given in SCREEN_ADDR @@ -1049,37 +1049,37 @@ __PLOTOVER: ld h, a ld de, (SCREEN_ADDR) add hl, de ;; Final screen addr - + LOCAL PO_ATTR_2 PO_ATTR_2 EQU 0BE4h ; Another entry to PO_ATTR call PO_ATTR_2 ; This will update attr accordingly. Beware, uses IY - + pop de pop hl - - LOCAL __FASTPLOTEND -__FASTPLOTEND: + + LOCAL __FASTPLOTEND +__FASTPLOTEND: or a ; Resets carry flag ex af, af' ; Recovers A reg ld a, e ret - + ENDP - + #line 45 "inktemp.bas" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -1087,38 +1087,38 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 46 "inktemp.bas" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -1132,42 +1132,42 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 47 "inktemp.bas" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register - - - + + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -1177,7 +1177,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -1185,40 +1185,40 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 48 "inktemp.bas" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -1229,17 +1229,17 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 49 "inktemp.bas" - - + + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/lcd3.asm b/tests/functional/lcd3.asm index 0d88dc9dd..cd42db1e0 100644 --- a/tests/functional/lcd3.asm +++ b/tests/functional/lcd3.asm @@ -154,40 +154,40 @@ __LABEL2: DEFB 4Fh DEFB 46h #line 1 "addf.asm" - + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -203,7 +203,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 2 "addf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) ; All of them uses A EDCB registers as 1st paramter. @@ -212,23 +212,23 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; ; Uses CALLEE convention ; ------------------------------------------------------------- - + __ADDF: ; Addition call __FPSTACK_PUSH2 - + ; ------------- ROM ADD rst 28h defb 0fh ; ADD defb 38h; ; END CALC - + jp __FPSTACK_POP - + #line 141 "lcd3.bas" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -236,25 +236,25 @@ __ADDF: ; Addition ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -263,41 +263,41 @@ __ADDF: ; Addition ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -305,25 +305,25 @@ __ADDF: ; Addition ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -332,39 +332,39 @@ __ADDF: ; Addition ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -372,56 +372,56 @@ __ADDF: ; Addition __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -430,57 +430,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -489,47 +489,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -539,57 +539,57 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 142 "lcd3.bas" #line 1 "ftou32reg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "ftou32reg.asm" - + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) PROC - + LOCAL __IS_FLOAT - + or a - jr nz, __IS_FLOAT + jr nz, __IS_FLOAT ; Here if it is a ZX ROM Integer - + ld h, c ld l, d ld a, e ; Takes sign: FF = -, 0 = + @@ -597,70 +597,70 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS inc a jp z, __NEG32 ; Negates if negative ret - + __IS_FLOAT: ; Jumps here if it is a true floating point number - ld h, e + ld h, e push hl ; Stores it for later (Contains Sign in H) - + push de push bc - + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + ;ld a, c ; Get exponent sub 128 ; Exponent -= 128 jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 - + __FTOU32REG_LOOP: exx ; Shift C'B' E'D' << 1, output bit stays in Carry sla d rl e rl b rl c - + exx ; Shift DEHL << 1, inserting the carry on the right rl l rl h rl e rl d - + djnz __FTOU32REG_LOOP - + __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative jp m, __NEG32 ; Negates DEHL - + ret - + ENDP - - + + __FTOU8: ; Converts float in C ED LH to Unsigned byte in A call __FTOU32REG ld a, l ret - + #line 143 "lcd3.bas" #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -668,25 +668,25 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -695,51 +695,51 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -747,12 +747,12 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -760,16 +760,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -781,27 +781,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -813,7 +813,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -821,15 +821,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -854,14 +854,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -869,25 +869,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -896,30 +896,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -927,17 +927,17 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 144 "lcd3.bas" #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -945,46 +945,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -997,67 +997,67 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - - - + + + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -1066,17 +1066,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -1084,26 +1084,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -1117,45 +1117,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -1166,28 +1166,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -1195,28 +1195,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -1225,83 +1225,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -1310,32 +1310,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -1345,7 +1345,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -1353,20 +1353,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -1376,7 +1376,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -1387,19 +1387,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -1409,7 +1409,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -1420,19 +1420,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -1442,7 +1442,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -1455,22 +1455,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -1479,79 +1479,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -1560,75 +1560,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -1638,7 +1638,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -1650,16 +1650,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1673,49 +1673,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1726,17 +1726,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1749,27 +1749,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1777,10 +1777,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1797,80 +1797,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1887,8 +1887,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1912,17 +1912,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1933,7 +1933,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1943,21 +1943,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1976,9 +1976,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -2003,58 +2003,58 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 145 "lcd3.bas" #line 1 "printstr.asm" - - - - - - + + + + + + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -2063,77 +2063,77 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 146 "lcd3.bas" #line 1 "pstorestr2.asm" - + ; vim:ts=4:et:sw=4 - ; + ; ; Stores an string (pointer to the HEAP by DE) into the address pointed ; by (IX + BC). No new copy of the string is created into the HEAP, since ; it's supposed it's already created (temporary string) ; - + #line 1 "storestr2.asm" - + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication ; HL = address of string memory variable ; DE = address of 2n string. It just copies DE into (HL) ; freeing (HL) previously. - - - + + + __PISTORE_STR2: ; Indirect store temporary string at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR2: ld c, (hl) ; Dereferences HL inc hl ld h, (hl) ld l, c ; HL = *HL (real string variable address) - + __STORE_STR2: push hl ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = *HL (real string address) - + push de call __MEM_FREE pop de - + pop hl ld (hl), e inc hl ld (hl), d dec hl ; HL points to mem address variable. This might be useful in the future. - + ret - + #line 9 "pstorestr2.asm" - + __PSTORE_STR2: push ix pop hl add hl, bc jp __STORE_STR2 - + #line 147 "lcd3.bas" #line 1 "pushf.asm" - - - ; Routine to push Float pointed by HL + + + ; Routine to push Float pointed by HL ; Into the stack. Notice that the hl points to the last ; byte of the FP number. ; Uses H'L' B'C' and D'E' to preserve ABCDEHL registers - + __FP_PUSH_REV: push hl exx @@ -2154,186 +2154,186 @@ __FP_PUSH_REV: push bc ; Return Address exx ret - - + + #line 148 "lcd3.bas" #line 1 "str.asm" - + ; The STR$( ) BASIC function implementation - + ; Given a FP number in C ED LH ; Returns a pointer (in HL) to the memory heap ; containing the FP number string representation - - - - - + + + + + __STR: - + __STR_FAST: - + PROC LOCAL __STR_END LOCAL RECLAIM2 LOCAL STK_END - + ld hl, (STK_END) push hl; Stores STK_END ld hl, (ATTR_T) ; Saves ATTR_T since it's changed by STR$ due to a ROM BUG push hl - + call __FPSTACK_PUSH ; Push number into stack rst 28h ; # Rom Calculator defb 2Eh ; # STR$(x) defb 38h ; # END CALC call __FPSTACK_POP ; Recovers string parameters to A ED CB (Only ED LH are important) - + pop hl ld (ATTR_T), hl ; Restores ATTR_T pop hl ld (STK_END), hl ; Balance STK_END to avoid STR$ bug - + push bc push de - + inc bc inc bc call __MEM_ALLOC ; HL Points to new block - + pop de pop bc - + push hl ld a, h or l jr z, __STR_END ; Return if NO MEMORY (NULL) - + push bc push de - ld (hl), c + ld (hl), c inc hl ld (hl), b inc hl ; Copies length - + ex de, hl ; HL = start of original string ldir ; Copies string content - + pop de ; Original (ROM-CALC) string pop bc ; Original Length - + __STR_END: ex de, hl inc bc - + call RECLAIM2 ; Frees TMP Memory pop hl ; String result - + ret - + RECLAIM2 EQU 19E8h STK_END EQU 5C65h - + ENDP - + #line 149 "lcd3.bas" #line 1 "strcat.asm" - - + + #line 1 "strlen.asm" - + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL - + __STRLEN: ; Direct FASTCALL entry ld a, h or l ret z - + ld a, (hl) inc hl ld h, (hl) ; LEN(str) in HL ld l, a ret - - + + #line 3 "strcat.asm" - + __ADDSTR: ; Implements c$ = a$ + b$ ; hl = &a$, de = &b$ (pointers) - - + + __STRCAT2: ; This routine creates a new string in dynamic space ; making room for it. Then copies a$ + b$ into it. ; HL = a$, DE = b$ - + PROC - + LOCAL __STR_CONT LOCAL __STRCATEND - + push hl call __STRLEN ld c, l ld b, h ; BC = LEN(a$) ex (sp), hl ; (SP) = LEN (a$), HL = a$ push hl ; Saves pointer to a$ - + inc bc inc bc ; +2 bytes to store length - + ex de, hl push hl call __STRLEN ; HL = len(b$) - + add hl, bc ; Total str length => 2 + len(a$) + len(b$) - + ld c, l ld b, h ; BC = Total str length + 2 - call __MEM_ALLOC - pop de ; HL = c$, DE = b$ - + call __MEM_ALLOC + pop de ; HL = c$, DE = b$ + ex de, hl ; HL = b$, DE = c$ - ex (sp), hl ; HL = a$, (SP) = b$ - + ex (sp), hl ; HL = a$, (SP) = b$ + exx - pop de ; D'E' = b$ + pop de ; D'E' = b$ exx - + pop bc ; LEN(a$) - + ld a, d or e ret z ; If no memory: RETURN - + __STR_CONT: push de ; Address of c$ - + ld a, h or l jr nz, __STR_CONT1 ; If len(a$) != 0 do copy - + ; a$ is NULL => uses HL = DE for transfer ld h, d ld l, e ld (hl), a ; This will copy 00 00 at (DE) location - inc de ; + inc de ; dec bc ; Ensure BC will be set to 1 in the next step - + __STR_CONT1: ; Copies a$ (HL) into c$ (DE) - inc bc + inc bc inc bc ; BC = BC + 2 ldir ; MEMCOPY: c$ = a$ pop hl ; HL = c$ - + exx push de ; Recovers b$; A ex hl,hl' would be very handy exx - - pop de ; DE = b$ - + + pop de ; DE = b$ + __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ; NOTE: Both DE, BC and AF are modified and lost ; Returns HL (pointer to a$) @@ -2341,53 +2341,53 @@ __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ld a, d or e ret z ; Returns if de is NULL (nothing to copy) - + push hl ; Saves HL to return it later - + ld c, (hl) inc hl ld b, (hl) inc hl add hl, bc ; HL = end of (a$) string ; bc = len(a$) push bc ; Saves LEN(a$) for later - + ex de, hl ; DE = end of string (Begin of copy addr) ld c, (hl) inc hl ld b, (hl) ; BC = len(b$) - + ld a, b or c jr z, __STRCATEND; Return if len(b$) == 0 - + push bc ; Save LEN(b$) inc hl ; Skip 2nd byte of len(b$) ldir ; Concatenate b$ - + pop bc ; Recovers length (b$) pop hl ; Recovers length (a$) add hl, bc ; HL = LEN(a$) + LEN(b$) = LEN(a$+b$) ex de, hl ; DE = LEN(a$+b$) pop hl - + ld (hl), e ; Updates new LEN and return inc hl ld (hl), d dec hl ret - + __STRCATEND: pop hl ; Removes Len(a$) pop hl ; Restores original HL, so HL = a$ ret - + ENDP - + #line 150 "lcd3.bas" - + #line 1 "u32tofreg.asm" - - + + __I8TOFREG: ld l, a rlca @@ -2395,35 +2395,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -2431,20 +2431,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -2452,32 +2452,32 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 152 "lcd3.bas" - + ZXBASIC_USER_DATA: _adr: DEFB 00, 00, 00, 00, 00 diff --git a/tests/functional/lcd5.asm b/tests/functional/lcd5.asm index d5c588e76..7ecb9465b 100644 --- a/tests/functional/lcd5.asm +++ b/tests/functional/lcd5.asm @@ -43,7 +43,7 @@ _SubLifetime__leave: ex (sp), hl exx ret - + ZXBASIC_USER_DATA: _tile: DEFW 0000h diff --git a/tests/functional/lcd6.asm b/tests/functional/lcd6.asm index f09d9c109..247dc1ede 100644 --- a/tests/functional/lcd6.asm +++ b/tests/functional/lcd6.asm @@ -57,7 +57,7 @@ _SubLifetime__leave: ex (sp), hl exx ret - + ZXBASIC_USER_DATA: _tile: DEFW 0000h diff --git a/tests/functional/lcd7.asm b/tests/functional/lcd7.asm index a68874f21..488bec41b 100644 --- a/tests/functional/lcd7.asm +++ b/tests/functional/lcd7.asm @@ -85,10 +85,10 @@ __LABEL0: DEFB 4Fh DEFB 4Bh #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -96,25 +96,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -123,41 +123,41 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -165,25 +165,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -192,39 +192,39 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -232,56 +232,56 @@ __LABEL0: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -290,57 +290,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -349,47 +349,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -399,17 +399,17 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 72 "lcd7.bas" #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -417,25 +417,25 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -444,51 +444,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -496,12 +496,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -509,16 +509,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -530,27 +530,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -562,7 +562,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -570,15 +570,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -603,14 +603,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -618,25 +618,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -645,30 +645,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -676,22 +676,22 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 73 "lcd7.bas" #line 1 "print_eol_attr.asm" - + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes - + #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -699,46 +699,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -751,67 +751,67 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - - - + + + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -820,17 +820,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -838,26 +838,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -871,45 +871,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -920,28 +920,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -949,28 +949,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -979,83 +979,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -1064,32 +1064,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -1099,7 +1099,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -1107,20 +1107,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -1130,7 +1130,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -1141,19 +1141,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -1163,7 +1163,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -1174,19 +1174,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -1196,7 +1196,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -1209,22 +1209,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -1233,79 +1233,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -1314,75 +1314,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -1392,7 +1392,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -1404,16 +1404,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1427,49 +1427,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1480,17 +1480,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1503,27 +1503,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1531,10 +1531,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1551,80 +1551,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1641,8 +1641,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1666,17 +1666,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1687,7 +1687,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1697,21 +1697,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1730,9 +1730,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1757,64 +1757,64 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 5 "print_eol_attr.asm" - - + + PRINT_EOL_ATTR: call PRINT_EOL jp COPY_ATTR #line 74 "lcd7.bas" #line 1 "printstr.asm" - - - - - - + + + + + + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1823,20 +1823,20 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 75 "lcd7.bas" #line 1 "pstorestr.asm" - + ; vim:ts=4:et:sw=4 - ; + ; ; Stores an string (pointer to the HEAP by DE) into the address pointed ; by (IX + BC). A new copy of the string is created into the HEAP ; - + #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -1847,15 +1847,15 @@ __PRINT_STR: ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1863,25 +1863,25 @@ __PRINT_STR: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1890,42 +1890,42 @@ __PRINT_STR: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - - - - + + + + + + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -1944,29 +1944,29 @@ __PRINT_STR: ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -1975,111 +1975,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -2095,7 +2095,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -2103,52 +2103,52 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 8 "pstorestr.asm" - + __PSTORE_STR: push ix pop hl add hl, bc jp __STORE_STR - + #line 76 "lcd7.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/lcd8.asm b/tests/functional/lcd8.asm index 2a43a3492..4e7742af2 100644 --- a/tests/functional/lcd8.asm +++ b/tests/functional/lcd8.asm @@ -87,10 +87,10 @@ __LABEL0: DEFB 4Fh DEFB 4Bh #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -98,25 +98,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -125,41 +125,41 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -167,25 +167,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -194,39 +194,39 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -234,56 +234,56 @@ __LABEL0: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -292,57 +292,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -351,47 +351,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -401,17 +401,17 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 74 "lcd8.bas" #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -419,25 +419,25 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -446,51 +446,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -498,12 +498,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -511,16 +511,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -532,27 +532,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -564,7 +564,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -572,15 +572,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -605,14 +605,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -620,25 +620,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -647,30 +647,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -678,22 +678,22 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 75 "lcd8.bas" #line 1 "print_eol_attr.asm" - + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes - + #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -701,46 +701,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -753,67 +753,67 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - - - + + + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -822,17 +822,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -840,26 +840,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -873,45 +873,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -922,28 +922,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -951,28 +951,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -981,83 +981,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -1066,32 +1066,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -1101,7 +1101,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -1109,20 +1109,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -1132,7 +1132,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -1143,19 +1143,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -1165,7 +1165,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -1176,19 +1176,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -1198,7 +1198,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -1211,22 +1211,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -1235,79 +1235,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -1316,75 +1316,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -1394,7 +1394,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -1406,16 +1406,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1429,49 +1429,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1482,17 +1482,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1505,27 +1505,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1533,10 +1533,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1553,80 +1553,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1643,8 +1643,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1668,17 +1668,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1689,7 +1689,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1699,21 +1699,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1732,9 +1732,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1759,64 +1759,64 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 5 "print_eol_attr.asm" - - + + PRINT_EOL_ATTR: call PRINT_EOL jp COPY_ATTR #line 76 "lcd8.bas" #line 1 "printstr.asm" - - - - - - + + + + + + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1825,11 +1825,11 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 77 "lcd8.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/lcd9.asm b/tests/functional/lcd9.asm index cb3601baa..158aa8ff6 100644 --- a/tests/functional/lcd9.asm +++ b/tests/functional/lcd9.asm @@ -75,10 +75,10 @@ __LABEL0: DEFB 4Fh DEFB 4Bh #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -86,25 +86,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -113,41 +113,41 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -155,25 +155,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -182,39 +182,39 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -222,56 +222,56 @@ __LABEL0: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -280,57 +280,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -339,47 +339,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -389,17 +389,17 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 62 "lcd9.bas" #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -407,25 +407,25 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -434,51 +434,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -486,12 +486,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -499,16 +499,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -520,27 +520,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -552,7 +552,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -560,15 +560,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -593,14 +593,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -608,25 +608,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -635,30 +635,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -666,22 +666,22 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 63 "lcd9.bas" #line 1 "print_eol_attr.asm" - + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes - + #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -689,46 +689,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -741,67 +741,67 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - - - + + + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -810,17 +810,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -828,26 +828,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -861,45 +861,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -910,28 +910,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -939,28 +939,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -969,83 +969,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -1054,32 +1054,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -1089,7 +1089,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -1097,20 +1097,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -1120,7 +1120,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -1131,19 +1131,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -1153,7 +1153,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -1164,19 +1164,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -1186,7 +1186,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -1199,22 +1199,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -1223,79 +1223,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -1304,75 +1304,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -1382,7 +1382,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -1394,16 +1394,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1417,49 +1417,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1470,17 +1470,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1493,27 +1493,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1521,10 +1521,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1541,80 +1541,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1631,8 +1631,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1656,17 +1656,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1677,7 +1677,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1687,21 +1687,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1720,9 +1720,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1747,64 +1747,64 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 5 "print_eol_attr.asm" - - + + PRINT_EOL_ATTR: call PRINT_EOL jp COPY_ATTR #line 64 "lcd9.bas" #line 1 "printstr.asm" - - - - - - + + + + + + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1813,12 +1813,12 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 65 "lcd9.bas" #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -1829,15 +1829,15 @@ __PRINT_STR: ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1845,25 +1845,25 @@ __PRINT_STR: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1872,42 +1872,42 @@ __PRINT_STR: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - - - - + + + + + + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -1926,29 +1926,29 @@ __PRINT_STR: ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -1957,111 +1957,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -2077,7 +2077,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -2085,44 +2085,44 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 66 "lcd9.bas" - + ZXBASIC_USER_DATA: _strg: DEFB 00, 00 diff --git a/tests/functional/lef16.asm b/tests/functional/lef16.asm index 9e0b7d417..aec8174a2 100644 --- a/tests/functional/lef16.asm +++ b/tests/functional/lef16.asm @@ -84,52 +84,52 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "lei32.asm" - - + + #line 1 "sub32.asm" - - ; SUB32 + + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) ; and returns result in DEHL. Carry an Z are set correctly - + __SUB32: exx pop bc ; saves return address in BC' exx - + or a ; clears carry flag ld b, h ; Operands come reversed => BC <- HL, HL = HL - BC ld c, l pop hl sbc hl, bc ex de, hl - + ld b, h ; High part (DE) now in HL. Repeat operation ld c, l pop hl sbc hl, bc ex de, hl ; DEHL now has de 32 bit result - + exx push bc ; puts return address back exx ret #line 3 "lei32.asm" - + __LEI32: ; Test 32 bit values Top of the stack <= HL,DE PROC LOCAL checkParity exx pop de ; Preserves return address exx - + call __SUB32 - + exx push de ; Puts return address back exx - + ex af, af' ld a, h or l @@ -137,7 +137,7 @@ __LEI32: ; Test 32 bit values Top of the stack <= HL,DE or d ld a, 1 ret z - + ex af, af' jp po, checkParity ld a, d @@ -150,10 +150,10 @@ checkParity: ENDP #line 75 "lef16.bas" #line 1 "swap32.asm" - + ; Exchanges current DE HL with the ; ones in the stack - + __SWAP32: pop bc ; Return address ex (sp), hl @@ -166,9 +166,9 @@ __SWAP32: inc sp push bc ret - + #line 76 "lef16.bas" - + ZXBASIC_USER_DATA: _level: DEFB 00h diff --git a/tests/functional/lei32.asm b/tests/functional/lei32.asm index 8b5e0dc73..43ca35253 100644 --- a/tests/functional/lei32.asm +++ b/tests/functional/lei32.asm @@ -97,52 +97,52 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "lei32.asm" - - + + #line 1 "sub32.asm" - - ; SUB32 + + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) ; and returns result in DEHL. Carry an Z are set correctly - + __SUB32: exx pop bc ; saves return address in BC' exx - + or a ; clears carry flag ld b, h ; Operands come reversed => BC <- HL, HL = HL - BC ld c, l pop hl sbc hl, bc ex de, hl - + ld b, h ; High part (DE) now in HL. Repeat operation ld c, l pop hl sbc hl, bc ex de, hl ; DEHL now has de 32 bit result - + exx push bc ; puts return address back exx ret #line 3 "lei32.asm" - + __LEI32: ; Test 32 bit values Top of the stack <= HL,DE PROC LOCAL checkParity exx pop de ; Preserves return address exx - + call __SUB32 - + exx push de ; Puts return address back exx - + ex af, af' ld a, h or l @@ -150,7 +150,7 @@ __LEI32: ; Test 32 bit values Top of the stack <= HL,DE or d ld a, 1 ret z - + ex af, af' jp po, checkParity ld a, d @@ -163,10 +163,10 @@ checkParity: ENDP #line 88 "lei32.bas" #line 1 "swap32.asm" - + ; Exchanges current DE HL with the ; ones in the stack - + __SWAP32: pop bc ; Return address ex (sp), hl @@ -179,9 +179,9 @@ __SWAP32: inc sp push bc ret - + #line 89 "lei32.bas" - + ZXBASIC_USER_DATA: _level: DEFB 01h diff --git a/tests/functional/let0.asm b/tests/functional/let0.asm index 1616a05db..dccad562a 100644 --- a/tests/functional/let0.asm +++ b/tests/functional/let0.asm @@ -30,7 +30,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 01h diff --git a/tests/functional/leu32.asm b/tests/functional/leu32.asm index d995b7356..ec2ff13a4 100644 --- a/tests/functional/leu32.asm +++ b/tests/functional/leu32.asm @@ -132,10 +132,10 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "swap32.asm" - + ; Exchanges current DE HL with the ; ones in the stack - + __SWAP32: pop bc ; Return address ex (sp), hl @@ -148,9 +148,9 @@ __SWAP32: inc sp push bc ret - + #line 123 "leu32.bas" - + ZXBASIC_USER_DATA: _level: DEFB 01h diff --git a/tests/functional/load02.asm b/tests/functional/load02.asm index 32e3db575..1f862d854 100644 --- a/tests/functional/load02.asm +++ b/tests/functional/load02.asm @@ -48,12 +48,12 @@ __LABEL0: DEFB 74h DEFB 31h #line 1 "load.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -61,25 +61,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -88,51 +88,51 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -140,12 +140,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -153,7 +153,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -161,10 +161,10 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -172,25 +172,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -199,39 +199,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -239,57 +239,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -301,27 +301,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -333,7 +333,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -341,15 +341,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -374,14 +374,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -389,25 +389,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "load.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -415,25 +415,25 @@ __MEM_SUBTRACT: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -442,38 +442,38 @@ __MEM_SUBTRACT: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -482,57 +482,57 @@ __MEM_SUBTRACT: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -541,47 +541,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -591,22 +591,22 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 3 "load.asm" #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -614,46 +614,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -666,67 +666,67 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - - - + + + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -735,17 +735,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -753,26 +753,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -786,45 +786,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -835,28 +835,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -864,28 +864,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -894,50 +894,50 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - + #line 63 "/src/zxb/trunk/library-asm/copy_attr.asm" ret #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -946,32 +946,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -981,7 +981,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -989,20 +989,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -1012,7 +1012,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -1023,19 +1023,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -1045,7 +1045,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -1056,19 +1056,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -1078,7 +1078,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -1091,22 +1091,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -1115,79 +1115,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -1196,75 +1196,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -1274,7 +1274,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -1286,16 +1286,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1309,49 +1309,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1362,17 +1362,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1385,27 +1385,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1413,10 +1413,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1433,80 +1433,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1523,8 +1523,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1548,17 +1548,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1569,7 +1569,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1579,21 +1579,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1612,9 +1612,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1639,12 +1639,12 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 4 "load.asm" - + LOAD_CODE: ; This function will implement the LOAD CODE Routine ; Parameters in the stack are HL => String with LOAD name @@ -1652,9 +1652,9 @@ LOAD_CODE: ; DE = START address of CODE to save ; BC = Length of data in bytes ; A = 1 => LOAD 0 => Verify - + PROC - + LOCAL LOAD_CONT, LOAD_CONT2, LOAD_CONT3 LOCAL LD_BYTES LOCAL LOAD_HEADER @@ -1665,50 +1665,50 @@ LOAD_CODE: LOCAL LD_CH_PR LOCAL LOAD_END LOCAL VR_CONTROL, VR_CONT_1, VR_CONT_2 - + HEAD1 EQU MEM0 + 8 ; Uses CALC Mem for temporary storage ; Must skip first 8 bytes used by ; PRINT routine TMP_HEADER EQU HEAD1 + 17 ; Temporary HEADER2 pointer storage - + LD_BYTES EQU 0556h ; ROM Routine LD-BYTES TMP_FLAG EQU 23655 ; Uses BREG as a Temporary FLAG - + pop hl ; Return address pop af ; A = 1 => LOAD; A = 0 => VERIFY pop bc ; data length in bytes pop de ; address start ex (sp), hl ; CALLE => now hl = String - + __LOAD_CODE: ; INLINE version push ix ; saves IX ld (TMP_FLAG), a ; Stores verify/load flag - + ; Prepares temporary 1st header descriptor ld ix, HEAD1 ld (ix + 0), 3 ; ZXBASIC ALWAYS uses CODE ld (ix + 1), 0FFh ; Wildcard for empty string - + ld (ix + 11), c ld (ix + 12), b ; Store length in bytes ld (ix + 13), e ld (ix + 14), d ; Store address in bytes - + ld a, h or l ld b, h ld c, l jr z, LOAD_HEADER ; NULL STRING => LOAD "" - + ld c, (hl) inc hl ld b, (hl) inc hl - + ld a, b or c jr z, LOAD_CONT2 ; NULL STRING => LOAD "" - + ; Fill with blanks push hl push bc @@ -1719,7 +1719,7 @@ __LOAD_CODE: ; INLINE version ldir pop bc pop hl - + LOAD_HEADER: ex de, hl ; Saves HL in DE ld hl, 10 @@ -1728,46 +1728,46 @@ LOAD_HEADER: ex de, hl ; Retrieve HL jr nc, LOAD_CONT ; Ok BC <= 10 ld bc, 10 ; BC at most 10 chars - + LOAD_CONT: ld de, HEAD1 + 1 ldir ; Copy String block NAME in header - + LOAD_CONT2: ld bc, 17; 2nd Header call __MEM_ALLOC - + ld a, h or l jr nz, LOAD_CONT3; there's memory - + ld a, ERROR_OutOfMemory jp __ERROR - + LOAD_CONT3: ld (TMP_HEADER), hl push hl pop ix - + ;; LD-LOOK-H --- RIPPED FROM ROM at 0x767 LD_LOOK_H: push ix ; save IX ld de, 17 ; seventeen bytes xor a ; reset zero flag scf ; set carry flag - + call LD_BYTES ; routine LD-BYTES loads a header from tape ; to second descriptor. pop ix ; restore IX jr nc, LD_LOOK_H ; loop back to LD-LOOK-H until header found. - + ld c, 80h ; C has bit 7 set to indicate header type mismatch as ; a default startpoint. - + ld a, (ix + 0) ; compare loaded type cp 3 ; with expected bytes header jr nz, LD_TYPE ; forward to LD-TYPE with mis-match. - + ld c, -10 ; set C to minus ten - will count characters ; up to zero. LD_TYPE: @@ -1779,22 +1779,22 @@ LD_TYPE: ld de, (TMP_HEADER) ; point DE to 2nd descriptor. ld b, 10 ; the count will be ten characters for the ; filename. - - ld a, (hl) ; fetch first character and test for + + ld a, (hl) ; fetch first character and test for inc a ; value 255. jr nz, LD_NAME ; forward to LD-NAME if not the wildcard. - + ; but if it is the wildcard, then add ten to C which is minus ten for a type ; match or -128 for a type mismatch. Although characters have to be counted ; bit 7 of C will not alter from state set here. - + ld a, c ; transfer $F6 or $80 to A - add a, b ; add 10 + add a, b ; add 10 ld c, a ; place result, zero or -118, in C. - + ; At this point we have either a type mismatch, a wildcard match or ten ; characters to be counted. The characters must be shown on the screen. - + ;; LD-NAME LD_NAME: inc de ; address next input character @@ -1802,32 +1802,32 @@ LD_NAME: cp (hl) ; compare to expected inc hl ; address next expected character jr nz, LD_CH_PR ; forward to LD-CH-PR with mismatch - + inc c ; increment matched character count - + ;; LD-CH-PR LD_CH_PR: call __PRINTCHAR ; PRINT-A prints character djnz LD_NAME ; loop back to LD-NAME for ten characters. - + bit 7, c ; test if all matched jr nz, LD_LOOK_H ; back to LD-LOOK-H if not - + ; else print a terminal carriage return. - + ld a, 0Dh ; prepare carriage return. call __PRINTCHAR ; PRINT-A outputs it. - + ld a, (HEAD1) cp 03 ; Only "bytes:" header is used un ZX BASIC jr nz, LD_LOOK_H - + ; Ok, ready to check for bytes start and end - + VR_CONTROL: ld e, (ix + 11) ; fetch length of new data ld d, (ix + 12) ; to DE. - + ld hl, HEAD1 + 11 ld a, (hl) ; fetch length of old data (orig. header) inc hl @@ -1838,7 +1838,7 @@ VR_CONTROL: ; e.g. LOAD "x" CODE sbc hl, de jr nz, LOAD_ERROR ; Lenghts don't match - + VR_CONT_1: ld hl, HEAD1 + 13 ; fetch start of old data (orig. header) ld a, (hl) @@ -1847,56 +1847,56 @@ VR_CONT_1: ld l, a or h ; check start for zero (unespecified) jr nz, VR_CONT_2 ; Jump if there was a start - + ld l, (ix + 13) ; otherwise use destination in header ld h, (ix + 14) ; and load code at addr. saved from - + VR_CONT_2: push hl pop ix ; Transfer load addr to IX - + ld a, (TMP_FLAG) ; load verify/load flag sra a ; shift bit 0 to Carry (1 => Load, 0 = Verify), A = 0 - dec a ; a = 0xFF (Data) + dec a ; a = 0xFF (Data) call LD_BYTES jr c, LOAD_END ; if carry, load/verification was ok - + LOAD_ERROR: ; Sets ERR_NR with Tape Loading, and returns ld a, ERROR_TapeLoadingErr ld (ERR_NR), a - + LOAD_END: pop ix ; Recovers stack frame pointer ld hl, (TMP_HEADER) ; Recovers tmp_header pointer jp MEM_FREE ; Returns via FREE_MEM, freeing tmp header - + ENDP - - + + PRINT_TAPE_MESSAGES: - + PROC - + LOCAL LOOK_NEXT_TAPE_MSG LOCAL PRINT_TAPE_MSG - + ; Print tape messages according to A value - ; Each message starts with a carriage return and + ; Each message starts with a carriage return and ; ends with last char having its bit 7 set - + ; A = 0 => '\nProgram: ' ; A = 1 => '\nNumber array: ' ; A = 2 => '\nCharacter array: ' ; A = 3 => '\nBytes: ' - + push bc - + ld hl, 09C0h ; address base of last 4 tape messages ld b, a inc b ; avoid 256-loop if b == 0 - ld a, 0Dh ; Msg start mark - + ld a, 0Dh ; Msg start mark + ; skip memory bytes looking for next tape msg entry ; each msg ends when 0Dh is fond LOOK_NEXT_TAPE_MSG: @@ -1905,32 +1905,32 @@ LOOK_NEXT_TAPE_MSG: jr nz, LOOK_NEXT_TAPE_MSG ; Ok next message found djnz LOOK_NEXT_TAPE_MSG ; Repeat if more msg to skip - + PRINT_TAPE_MSG: ; Ok. This will print bytes after (HL) ; until one of them has bit 7 set ld a, (hl) and 7Fh ; Clear bit 7 of A call __PRINTCHAR - + ld a, (hl) inc hl add a, a ; Carry if A >= 128 jr nc, PRINT_TAPE_MSG - + pop bc ret - + ENDP #line 35 "load02.bas" #line 1 "loadstr.asm" - - - + + + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -1939,37 +1939,37 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) pop hl ; Recovers destiny in hl as result ret #line 36 "load02.bas" - + ZXBASIC_USER_DATA: _variableToSave: DEFB 00, 00 diff --git a/tests/functional/load03.asm b/tests/functional/load03.asm index 631719d45..66d9f5cbf 100644 --- a/tests/functional/load03.asm +++ b/tests/functional/load03.asm @@ -47,12 +47,12 @@ __LABEL0: DEFB 73h DEFB 74h #line 1 "load.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -60,25 +60,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -87,51 +87,51 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -139,12 +139,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -152,7 +152,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -160,10 +160,10 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -171,25 +171,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -198,39 +198,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -238,57 +238,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -300,27 +300,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -332,7 +332,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -340,15 +340,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -373,14 +373,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -388,25 +388,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "load.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -414,25 +414,25 @@ __MEM_SUBTRACT: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -441,38 +441,38 @@ __MEM_SUBTRACT: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -481,57 +481,57 @@ __MEM_SUBTRACT: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -540,47 +540,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -590,22 +590,22 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 3 "load.asm" #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -613,46 +613,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -665,67 +665,67 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - - - + + + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -734,17 +734,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -752,26 +752,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -785,45 +785,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -834,28 +834,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -863,28 +863,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -893,50 +893,50 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - + #line 63 "/src/zxb/trunk/library-asm/copy_attr.asm" ret #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -945,32 +945,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -980,7 +980,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -988,20 +988,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -1011,7 +1011,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -1022,19 +1022,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -1044,7 +1044,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -1055,19 +1055,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -1077,7 +1077,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -1090,22 +1090,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -1114,79 +1114,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -1195,75 +1195,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -1273,7 +1273,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -1285,16 +1285,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1308,49 +1308,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1361,17 +1361,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1384,27 +1384,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1412,10 +1412,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1432,80 +1432,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1522,8 +1522,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1547,17 +1547,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1568,7 +1568,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1578,21 +1578,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1611,9 +1611,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1638,12 +1638,12 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 4 "load.asm" - + LOAD_CODE: ; This function will implement the LOAD CODE Routine ; Parameters in the stack are HL => String with LOAD name @@ -1651,9 +1651,9 @@ LOAD_CODE: ; DE = START address of CODE to save ; BC = Length of data in bytes ; A = 1 => LOAD 0 => Verify - + PROC - + LOCAL LOAD_CONT, LOAD_CONT2, LOAD_CONT3 LOCAL LD_BYTES LOCAL LOAD_HEADER @@ -1664,50 +1664,50 @@ LOAD_CODE: LOCAL LD_CH_PR LOCAL LOAD_END LOCAL VR_CONTROL, VR_CONT_1, VR_CONT_2 - + HEAD1 EQU MEM0 + 8 ; Uses CALC Mem for temporary storage ; Must skip first 8 bytes used by ; PRINT routine TMP_HEADER EQU HEAD1 + 17 ; Temporary HEADER2 pointer storage - + LD_BYTES EQU 0556h ; ROM Routine LD-BYTES TMP_FLAG EQU 23655 ; Uses BREG as a Temporary FLAG - + pop hl ; Return address pop af ; A = 1 => LOAD; A = 0 => VERIFY pop bc ; data length in bytes pop de ; address start ex (sp), hl ; CALLE => now hl = String - + __LOAD_CODE: ; INLINE version push ix ; saves IX ld (TMP_FLAG), a ; Stores verify/load flag - + ; Prepares temporary 1st header descriptor ld ix, HEAD1 ld (ix + 0), 3 ; ZXBASIC ALWAYS uses CODE ld (ix + 1), 0FFh ; Wildcard for empty string - + ld (ix + 11), c ld (ix + 12), b ; Store length in bytes ld (ix + 13), e ld (ix + 14), d ; Store address in bytes - + ld a, h or l ld b, h ld c, l jr z, LOAD_HEADER ; NULL STRING => LOAD "" - + ld c, (hl) inc hl ld b, (hl) inc hl - + ld a, b or c jr z, LOAD_CONT2 ; NULL STRING => LOAD "" - + ; Fill with blanks push hl push bc @@ -1718,7 +1718,7 @@ __LOAD_CODE: ; INLINE version ldir pop bc pop hl - + LOAD_HEADER: ex de, hl ; Saves HL in DE ld hl, 10 @@ -1727,46 +1727,46 @@ LOAD_HEADER: ex de, hl ; Retrieve HL jr nc, LOAD_CONT ; Ok BC <= 10 ld bc, 10 ; BC at most 10 chars - + LOAD_CONT: ld de, HEAD1 + 1 ldir ; Copy String block NAME in header - + LOAD_CONT2: ld bc, 17; 2nd Header call __MEM_ALLOC - + ld a, h or l jr nz, LOAD_CONT3; there's memory - + ld a, ERROR_OutOfMemory jp __ERROR - + LOAD_CONT3: ld (TMP_HEADER), hl push hl pop ix - + ;; LD-LOOK-H --- RIPPED FROM ROM at 0x767 LD_LOOK_H: push ix ; save IX ld de, 17 ; seventeen bytes xor a ; reset zero flag scf ; set carry flag - + call LD_BYTES ; routine LD-BYTES loads a header from tape ; to second descriptor. pop ix ; restore IX jr nc, LD_LOOK_H ; loop back to LD-LOOK-H until header found. - + ld c, 80h ; C has bit 7 set to indicate header type mismatch as ; a default startpoint. - + ld a, (ix + 0) ; compare loaded type cp 3 ; with expected bytes header jr nz, LD_TYPE ; forward to LD-TYPE with mis-match. - + ld c, -10 ; set C to minus ten - will count characters ; up to zero. LD_TYPE: @@ -1778,22 +1778,22 @@ LD_TYPE: ld de, (TMP_HEADER) ; point DE to 2nd descriptor. ld b, 10 ; the count will be ten characters for the ; filename. - - ld a, (hl) ; fetch first character and test for + + ld a, (hl) ; fetch first character and test for inc a ; value 255. jr nz, LD_NAME ; forward to LD-NAME if not the wildcard. - + ; but if it is the wildcard, then add ten to C which is minus ten for a type ; match or -128 for a type mismatch. Although characters have to be counted ; bit 7 of C will not alter from state set here. - + ld a, c ; transfer $F6 or $80 to A - add a, b ; add 10 + add a, b ; add 10 ld c, a ; place result, zero or -118, in C. - + ; At this point we have either a type mismatch, a wildcard match or ten ; characters to be counted. The characters must be shown on the screen. - + ;; LD-NAME LD_NAME: inc de ; address next input character @@ -1801,32 +1801,32 @@ LD_NAME: cp (hl) ; compare to expected inc hl ; address next expected character jr nz, LD_CH_PR ; forward to LD-CH-PR with mismatch - + inc c ; increment matched character count - + ;; LD-CH-PR LD_CH_PR: call __PRINTCHAR ; PRINT-A prints character djnz LD_NAME ; loop back to LD-NAME for ten characters. - + bit 7, c ; test if all matched jr nz, LD_LOOK_H ; back to LD-LOOK-H if not - + ; else print a terminal carriage return. - + ld a, 0Dh ; prepare carriage return. call __PRINTCHAR ; PRINT-A outputs it. - + ld a, (HEAD1) cp 03 ; Only "bytes:" header is used un ZX BASIC jr nz, LD_LOOK_H - + ; Ok, ready to check for bytes start and end - + VR_CONTROL: ld e, (ix + 11) ; fetch length of new data ld d, (ix + 12) ; to DE. - + ld hl, HEAD1 + 11 ld a, (hl) ; fetch length of old data (orig. header) inc hl @@ -1837,7 +1837,7 @@ VR_CONTROL: ; e.g. LOAD "x" CODE sbc hl, de jr nz, LOAD_ERROR ; Lenghts don't match - + VR_CONT_1: ld hl, HEAD1 + 13 ; fetch start of old data (orig. header) ld a, (hl) @@ -1846,56 +1846,56 @@ VR_CONT_1: ld l, a or h ; check start for zero (unespecified) jr nz, VR_CONT_2 ; Jump if there was a start - + ld l, (ix + 13) ; otherwise use destination in header ld h, (ix + 14) ; and load code at addr. saved from - + VR_CONT_2: push hl pop ix ; Transfer load addr to IX - + ld a, (TMP_FLAG) ; load verify/load flag sra a ; shift bit 0 to Carry (1 => Load, 0 = Verify), A = 0 - dec a ; a = 0xFF (Data) + dec a ; a = 0xFF (Data) call LD_BYTES jr c, LOAD_END ; if carry, load/verification was ok - + LOAD_ERROR: ; Sets ERR_NR with Tape Loading, and returns ld a, ERROR_TapeLoadingErr ld (ERR_NR), a - + LOAD_END: pop ix ; Recovers stack frame pointer ld hl, (TMP_HEADER) ; Recovers tmp_header pointer jp MEM_FREE ; Returns via FREE_MEM, freeing tmp header - + ENDP - - + + PRINT_TAPE_MESSAGES: - + PROC - + LOCAL LOOK_NEXT_TAPE_MSG LOCAL PRINT_TAPE_MSG - + ; Print tape messages according to A value - ; Each message starts with a carriage return and + ; Each message starts with a carriage return and ; ends with last char having its bit 7 set - + ; A = 0 => '\nProgram: ' ; A = 1 => '\nNumber array: ' ; A = 2 => '\nCharacter array: ' ; A = 3 => '\nBytes: ' - + push bc - + ld hl, 09C0h ; address base of last 4 tape messages ld b, a inc b ; avoid 256-loop if b == 0 - ld a, 0Dh ; Msg start mark - + ld a, 0Dh ; Msg start mark + ; skip memory bytes looking for next tape msg entry ; each msg ends when 0Dh is fond LOOK_NEXT_TAPE_MSG: @@ -1904,32 +1904,32 @@ LOOK_NEXT_TAPE_MSG: jr nz, LOOK_NEXT_TAPE_MSG ; Ok next message found djnz LOOK_NEXT_TAPE_MSG ; Repeat if more msg to skip - + PRINT_TAPE_MSG: ; Ok. This will print bytes after (HL) ; until one of them has bit 7 set ld a, (hl) and 7Fh ; Clear bit 7 of A call __PRINTCHAR - + ld a, (hl) inc hl add a, a ; Carry if A >= 128 jr nc, PRINT_TAPE_MSG - + pop bc ret - + ENDP #line 34 "load03.bas" #line 1 "loadstr.asm" - - - + + + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -1938,37 +1938,37 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) pop hl ; Recovers destiny in hl as result ret #line 35 "load03.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/loadstr.asm b/tests/functional/loadstr.asm index 653869dd2..15ae45527 100644 --- a/tests/functional/loadstr.asm +++ b/tests/functional/loadstr.asm @@ -44,7 +44,7 @@ __LABEL0: DEFB 31h DEFB 30h #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -55,15 +55,15 @@ __LABEL0: ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -71,25 +71,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -98,52 +98,52 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -151,12 +151,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -164,7 +164,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -172,10 +172,10 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -183,25 +183,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -210,42 +210,42 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -253,25 +253,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -280,39 +280,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -320,57 +320,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -382,27 +382,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -414,7 +414,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -422,15 +422,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -455,14 +455,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -470,25 +470,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 71 "realloc.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -496,25 +496,25 @@ __MEM_SUBTRACT: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -523,38 +523,38 @@ __MEM_SUBTRACT: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -563,57 +563,57 @@ __MEM_SUBTRACT: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -622,47 +622,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -672,12 +672,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 72 "realloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -696,29 +696,29 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -727,111 +727,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -847,7 +847,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -855,127 +855,127 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 32 "loadstr.bas" #line 1 "storestr2.asm" - + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication ; HL = address of string memory variable ; DE = address of 2n string. It just copies DE into (HL) ; freeing (HL) previously. - - - + + + __PISTORE_STR2: ; Indirect store temporary string at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR2: ld c, (hl) ; Dereferences HL inc hl ld h, (hl) ld l, c ; HL = *HL (real string variable address) - + __STORE_STR2: push hl ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = *HL (real string address) - + push de call __MEM_FREE pop de - + pop hl ld (hl), e inc hl ld (hl), d dec hl ; HL points to mem address variable. This might be useful in the future. - + ret - + #line 33 "loadstr.bas" #line 1 "str.asm" - + ; The STR$( ) BASIC function implementation - + ; Given a FP number in C ED LH ; Returns a pointer (in HL) to the memory heap ; containing the FP number string representation - - + + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -992,9 +992,9 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK jp __FPSTACK_PUSH #line 9 "str.asm" #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -1002,90 +1002,90 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 10 "str.asm" - + __STR: - + __STR_FAST: - + PROC LOCAL __STR_END LOCAL RECLAIM2 LOCAL STK_END - + ld hl, (STK_END) push hl; Stores STK_END ld hl, (ATTR_T) ; Saves ATTR_T since it's changed by STR$ due to a ROM BUG push hl - + call __FPSTACK_PUSH ; Push number into stack rst 28h ; # Rom Calculator defb 2Eh ; # STR$(x) defb 38h ; # END CALC call __FPSTACK_POP ; Recovers string parameters to A ED CB (Only ED LH are important) - + pop hl ld (ATTR_T), hl ; Restores ATTR_T pop hl ld (STK_END), hl ; Balance STK_END to avoid STR$ bug - + push bc push de - + inc bc inc bc call __MEM_ALLOC ; HL Points to new block - + pop de pop bc - + push hl ld a, h or l jr z, __STR_END ; Return if NO MEMORY (NULL) - + push bc push de - ld (hl), c + ld (hl), c inc hl ld (hl), b inc hl ; Copies length - + ex de, hl ; HL = start of original string ldir ; Copies string content - + pop de ; Original (ROM-CALC) string pop bc ; Original Length - + __STR_END: ex de, hl inc bc - + call RECLAIM2 ; Frees TMP Memory pop hl ; String result - + ret - + RECLAIM2 EQU 19E8h STK_END EQU 5C65h - + ENDP - + #line 34 "loadstr.bas" #line 1 "val.asm" - - - - - + + + + + VAL: ; Computes VAL(a$) using ROM FP-CALC ; HL = address of a$ ; Returns FP number in C ED LH registers ; A Register = 1 => Free a$ on return - + PROC - + LOCAL STK_STO_S LOCAL __RET_ZERO LOCAL ERR_SP @@ -1095,107 +1095,107 @@ VAL: ; Computes VAL(a$) using ROM FP-CALC LOCAL __VAL_ERROR LOCAL __VAL_EMPTY LOCAL SET_MIN - + RECLAIM1 EQU 6629 STKBOT EQU 23651 ERR_SP EQU 23613 CH_ADD EQU 23645 STK_STO_S EQU 2AB2h SET_MIN EQU 16B0h - + ld d, a ; Preserves A register in DE ld a, h or l - jr z, __RET_ZERO ; NULL STRING => Return 0 - + jr z, __RET_ZERO ; NULL STRING => Return 0 + push de ; Saves A Register (now in D) push hl ; Not null string. Save its address for later - + ld c, (hl) inc hl ld b, (hl) inc hl - + ld a, b or c jr z, __VAL_EMPTY ; Jumps VAL_EMPTY on empty string - + ex de, hl ; DE = String start - + ld hl, (CH_ADD) push hl - + ld hl, (STKBOT) push hl - + ld hl, (ERR_SP) push hl - + ;; Now put our error handler on ERR_SP ld hl, __VAL_ERROR push hl ld hl, 0 add hl, sp ld (ERR_SP), hl - + call STK_STO_S ; Enter it on the stack - + ld b, 1Dh ; "VAL" rst 28h ; ROM CALC defb 1Dh ; VAL defb 38h ; END CALC - + pop hl ; Discards our current error handler pop hl ld (ERR_SP), hl ; Restores ERR_SP - + pop de ; old STKBOT ld hl, (STKBOT) ; current SKTBOT call RECLAIM1 ; Recover unused space - + pop hl ; Discards old CH_ADD value pop hl ; String pointer pop af ; Deletion flag or a call nz, __MEM_FREE ; Frees string content before returning - + ld a, ERROR_Ok ; Sets OK in the result ld (ERR_NR), a - + jp __FPSTACK_POP ; Recovers result and return from there - + __VAL_ERROR: ; Jumps here on ERROR pop hl ld (ERR_SP), hl ; Restores ERR_SP - + ld hl, (STKBOT) ; current SKTBOT pop de ; old STKBOT pop hl ld (CH_ADD), hl ; Recovers old CH_ADD - + call 16B0h ; Resets temporary areas after an error - + __VAL_EMPTY: ; Jumps here on empty string pop hl ; Recovers initial string address pop af ; String flag: If not 0 => it's temporary or a call nz, __MEM_FREE ; Frees "" string - + __RET_ZERO: ; Returns 0 Floating point on error ld a, ERROR_Ok ld (ERR_NR), a - + xor a ld b, a ld c, a ld d, b ld e, c ret - + ENDP - + #line 35 "loadstr.bas" - + ZXBASIC_USER_DATA: _b: DEFB 00, 00 diff --git a/tests/functional/loadu16ii.asm b/tests/functional/loadu16ii.asm index c07dc8a27..fcf7e14bd 100644 --- a/tests/functional/loadu16ii.asm +++ b/tests/functional/loadu16ii.asm @@ -53,19 +53,19 @@ __LABEL__test: ld c, l jp __END_PROGRAM #line 1 "mul16.asm" - + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned - + PROC - + LOCAL __MUL16LOOP LOCAL __MUL16NOADD - + ex de, hl pop hl ; Return address ex (sp), hl ; CALLEE caller convention - + ;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand ;; ld c, h ;; ld a, l ; C,A => 1st Operand @@ -83,43 +83,43 @@ __MUL16: ; Mutiplies HL with the last value stored into de stack ;;__MUL16NOADD: ;; sla e ;; rl d - ;; + ;; ;; djnz __MUL16LOOP - + __MUL16_FAST: ld b, 16 ld a, d ld c, e ex de, hl ld hl, 0 - + __MUL16LOOP: add hl, hl ; hl << 1 sla c rla ; a,c << 1 jp nc, __MUL16NOADD add hl, de - + __MUL16NOADD: djnz __MUL16LOOP - + ret ; Result in hl (16 lower bits) - + ENDP - + #line 43 "loadu16ii.bas" #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -127,46 +127,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -179,43 +179,43 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -223,12 +223,12 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -236,51 +236,51 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "in_screen.asm" - + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -289,17 +289,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -307,26 +307,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -340,45 +340,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -389,28 +389,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -418,28 +418,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -448,83 +448,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -533,32 +533,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -568,7 +568,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -576,20 +576,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -599,7 +599,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -610,19 +610,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -632,7 +632,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -643,19 +643,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -665,7 +665,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -678,22 +678,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -702,79 +702,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -783,75 +783,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -861,7 +861,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -873,16 +873,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -896,49 +896,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -949,17 +949,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -972,27 +972,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1000,10 +1000,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1020,80 +1020,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1110,8 +1110,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1135,17 +1135,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1156,7 +1156,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1166,21 +1166,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1199,9 +1199,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1226,33 +1226,33 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 44 "loadu16ii.bas" #line 1 "printu16.asm" - + #line 1 "printi16.asm" - + #line 1 "printnum.asm" - - - - + + + + __PRINTU_START: PROC - + LOCAL __PRINTU_CONT - + ld a, b or a jp nz, __PRINTU_CONT - + ld a, '0' jp __PRINT_DIGIT - - + + __PRINTU_CONT: pop af push bc @@ -1260,30 +1260,30 @@ __PRINTU_CONT: pop bc djnz __PRINTU_CONT ret - + ENDP - - + + __PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers ld a, '-' jp __PRINT_DIGIT - + __PRINT_DIGIT EQU __PRINTCHAR ; PRINTS the char in A register, and puts its attrs - - + + #line 2 "printi16.asm" #line 1 "div16.asm" - - ; 16 bit division and modulo functions + + ; 16 bit division and modulo functions ; for both signed and unsigned values - + #line 1 "neg16.asm" - + ; Negates HL value (16 bit) __ABS16: bit 7, h ret z - + __NEGHL: ld a, l ; HL = -HL cpl @@ -1293,23 +1293,23 @@ __NEGHL: ld h, a inc hl ret - + #line 5 "div16.asm" - + __DIVU16: ; 16 bit unsigned division ; HL = Dividend, Stack Top = Divisor - + ; -- OBSOLETE ; Now uses FASTCALL convention ; ex de, hl ; pop hl ; Return address ; ex (sp), hl ; CALLEE Convention - + __DIVU16_FAST: ld a, h ld c, l ld hl, 0 ld b, 16 - + __DIV16LOOP: sll c rla @@ -1318,46 +1318,46 @@ __DIV16LOOP: jr nc, __DIV16NOADD add hl,de dec c - + __DIV16NOADD: djnz __DIV16LOOP - + ex de, hl ld h, a ld l, c - + ret ; HL = quotient, DE = Mudulus - - - + + + __MODU16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVU16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - - + + __DIVI16: ; 16 bit signed division ; --- The following is OBSOLETE --- ; ex de, hl ; pop hl ; ex (sp), hl ; CALLEE Convention - + __DIVI16_FAST: ld a, d xor h ex af, af' ; BIT 7 of a contains result - + bit 7, d ; DE is negative? - jr z, __DIVI16A - + jr z, __DIVI16A + ld a, e ; DE = -DE cpl ld e, a @@ -1365,75 +1365,75 @@ __DIVI16_FAST: cpl ld d, a inc de - + __DIVI16A: bit 7, h ; HL is negative? call nz, __NEGHL - + __DIVI16B: call __DIVU16_FAST ex af, af' - - or a + + or a ret p ; return if positive jp __NEGHL - - + + __MODI16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVI16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - + #line 3 "printi16.asm" - - - + + + __PRINTI16: ; Prints a 16bits signed in HL ; Converts 16 to 32 bits PROC - + LOCAL __PRINTU_LOOP ld a, h or a - + jp p, __PRINTU16 - + call __PRINT_MINUS call __NEGHL - + __PRINTU16: - + ld b, 0 __PRINTU_LOOP: ld a, h or l jp z, __PRINTU_START - + push bc ld de, 10 call __DIVU16_FAST ; Divides by DE. DE = MODULUS at exit. Since < 256, E = Modulus pop bc - + ld a, e or '0' ; Stores ASCII digit (must be print in reversed order) push af inc b jp __PRINTU_LOOP ; Uses JP in loops - + ENDP - + #line 2 "printu16.asm" - + #line 45 "loadu16ii.bas" - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/localdim.asm b/tests/functional/localdim.asm index 8092550ee..79ef97082 100644 --- a/tests/functional/localdim.asm +++ b/tests/functional/localdim.asm @@ -57,7 +57,7 @@ _test__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: __LABEL0: DEFB 01h diff --git a/tests/functional/ltee1.asm b/tests/functional/ltee1.asm index 8d0983b37..3ebada3bf 100644 --- a/tests/functional/ltee1.asm +++ b/tests/functional/ltee1.asm @@ -101,10 +101,10 @@ __LABEL1: DEFB 6Ch DEFB 65h #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -112,25 +112,25 @@ __LABEL1: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -139,41 +139,41 @@ __LABEL1: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -181,25 +181,25 @@ __LABEL1: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -208,39 +208,39 @@ __LABEL1: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -248,56 +248,56 @@ __LABEL1: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -306,57 +306,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -365,47 +365,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -415,17 +415,17 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 88 "ltee1.bas" #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -433,25 +433,25 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -460,51 +460,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -512,12 +512,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -525,16 +525,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -546,27 +546,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -578,7 +578,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -586,15 +586,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -619,14 +619,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -634,25 +634,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -661,30 +661,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -692,22 +692,22 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 89 "ltee1.bas" #line 1 "print_eol_attr.asm" - + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes - + #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -715,46 +715,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -767,67 +767,67 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - - - + + + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -836,17 +836,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -854,26 +854,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -887,45 +887,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -936,28 +936,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -965,28 +965,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -995,83 +995,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -1080,32 +1080,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -1115,7 +1115,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -1123,20 +1123,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -1146,7 +1146,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -1157,19 +1157,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -1179,7 +1179,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -1190,19 +1190,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -1212,7 +1212,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -1225,22 +1225,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -1249,79 +1249,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -1330,75 +1330,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -1408,7 +1408,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -1420,16 +1420,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1443,49 +1443,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1496,17 +1496,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1519,27 +1519,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1547,10 +1547,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1567,80 +1567,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1657,8 +1657,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1682,17 +1682,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1703,7 +1703,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1713,21 +1713,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1746,9 +1746,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1773,64 +1773,64 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 5 "print_eol_attr.asm" - - + + PRINT_EOL_ATTR: call PRINT_EOL jp COPY_ATTR #line 90 "ltee1.bas" #line 1 "printstr.asm" - - - - - - + + + + + + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1839,20 +1839,20 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 91 "ltee1.bas" #line 1 "pstorestr.asm" - + ; vim:ts=4:et:sw=4 - ; + ; ; Stores an string (pointer to the HEAP by DE) into the address pointed ; by (IX + BC). A new copy of the string is created into the HEAP ; - + #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -1863,15 +1863,15 @@ __PRINT_STR: ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1879,25 +1879,25 @@ __PRINT_STR: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1906,42 +1906,42 @@ __PRINT_STR: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - - - - + + + + + + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -1960,29 +1960,29 @@ __PRINT_STR: ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -1991,111 +1991,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -2111,7 +2111,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -2119,208 +2119,208 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 8 "pstorestr.asm" - + __PSTORE_STR: push ix pop hl add hl, bc jp __STORE_STR - + #line 92 "ltee1.bas" #line 1 "pstorestr2.asm" - + ; vim:ts=4:et:sw=4 - ; + ; ; Stores an string (pointer to the HEAP by DE) into the address pointed ; by (IX + BC). No new copy of the string is created into the HEAP, since ; it's supposed it's already created (temporary string) ; - + #line 1 "storestr2.asm" - + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication ; HL = address of string memory variable ; DE = address of 2n string. It just copies DE into (HL) ; freeing (HL) previously. - - - + + + __PISTORE_STR2: ; Indirect store temporary string at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR2: ld c, (hl) ; Dereferences HL inc hl ld h, (hl) ld l, c ; HL = *HL (real string variable address) - + __STORE_STR2: push hl ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = *HL (real string address) - + push de call __MEM_FREE pop de - + pop hl ld (hl), e inc hl ld (hl), d dec hl ; HL points to mem address variable. This might be useful in the future. - + ret - + #line 9 "pstorestr2.asm" - + __PSTORE_STR2: push ix pop hl add hl, bc jp __STORE_STR2 - + #line 93 "ltee1.bas" - + #line 1 "strcat.asm" - - + + #line 1 "strlen.asm" - + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL - + __STRLEN: ; Direct FASTCALL entry ld a, h or l ret z - + ld a, (hl) inc hl ld h, (hl) ; LEN(str) in HL ld l, a ret - - + + #line 3 "strcat.asm" - + __ADDSTR: ; Implements c$ = a$ + b$ ; hl = &a$, de = &b$ (pointers) - - + + __STRCAT2: ; This routine creates a new string in dynamic space ; making room for it. Then copies a$ + b$ into it. ; HL = a$, DE = b$ - + PROC - + LOCAL __STR_CONT LOCAL __STRCATEND - + push hl call __STRLEN ld c, l ld b, h ; BC = LEN(a$) ex (sp), hl ; (SP) = LEN (a$), HL = a$ push hl ; Saves pointer to a$ - + inc bc inc bc ; +2 bytes to store length - + ex de, hl push hl call __STRLEN ; HL = len(b$) - + add hl, bc ; Total str length => 2 + len(a$) + len(b$) - + ld c, l ld b, h ; BC = Total str length + 2 - call __MEM_ALLOC - pop de ; HL = c$, DE = b$ - + call __MEM_ALLOC + pop de ; HL = c$, DE = b$ + ex de, hl ; HL = b$, DE = c$ - ex (sp), hl ; HL = a$, (SP) = b$ - + ex (sp), hl ; HL = a$, (SP) = b$ + exx - pop de ; D'E' = b$ + pop de ; D'E' = b$ exx - + pop bc ; LEN(a$) - + ld a, d or e ret z ; If no memory: RETURN - + __STR_CONT: push de ; Address of c$ - + ld a, h or l jr nz, __STR_CONT1 ; If len(a$) != 0 do copy - + ; a$ is NULL => uses HL = DE for transfer ld h, d ld l, e ld (hl), a ; This will copy 00 00 at (DE) location - inc de ; + inc de ; dec bc ; Ensure BC will be set to 1 in the next step - + __STR_CONT1: ; Copies a$ (HL) into c$ (DE) - inc bc + inc bc inc bc ; BC = BC + 2 ldir ; MEMCOPY: c$ = a$ pop hl ; HL = c$ - + exx push de ; Recovers b$; A ex hl,hl' would be very handy exx - - pop de ; DE = b$ - + + pop de ; DE = b$ + __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ; NOTE: Both DE, BC and AF are modified and lost ; Returns HL (pointer to a$) @@ -2328,50 +2328,50 @@ __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ld a, d or e ret z ; Returns if de is NULL (nothing to copy) - + push hl ; Saves HL to return it later - + ld c, (hl) inc hl ld b, (hl) inc hl add hl, bc ; HL = end of (a$) string ; bc = len(a$) push bc ; Saves LEN(a$) for later - + ex de, hl ; DE = end of string (Begin of copy addr) ld c, (hl) inc hl ld b, (hl) ; BC = len(b$) - + ld a, b or c jr z, __STRCATEND; Return if len(b$) == 0 - + push bc ; Save LEN(b$) inc hl ; Skip 2nd byte of len(b$) ldir ; Concatenate b$ - + pop bc ; Recovers length (b$) pop hl ; Recovers length (a$) add hl, bc ; HL = LEN(a$) + LEN(b$) = LEN(a$+b$) ex de, hl ; DE = LEN(a$+b$) pop hl - + ld (hl), e ; Updates new LEN and return inc hl ld (hl), d dec hl ret - + __STRCATEND: pop hl ; Removes Len(a$) pop hl ; Restores original HL, so HL = a$ ret - + ENDP - + #line 95 "ltee1.bas" - + ZXBASIC_USER_DATA: _newMsg: DEFB 00, 00 diff --git a/tests/functional/ltee10.asm b/tests/functional/ltee10.asm index c607a54c9..cd6491273 100644 --- a/tests/functional/ltee10.asm +++ b/tests/functional/ltee10.asm @@ -57,10 +57,10 @@ _setlocal__leave: pop ix ret #line 1 "array.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ------------------------------------------------------------------- ; Simple array Index routine @@ -68,28 +68,28 @@ _setlocal__leave: ; HL = Start of array memory (First two bytes contains N-1 dimensions) ; Dimension values on the stack, (top of the stack, highest dimension) ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> - + ; For any array of N dimension A(aN-1, ..., a1, a0) ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] ; What I will do here is to calculate the following sequence: ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... - - + + #line 1 "mul16.asm" - + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned - + PROC - + LOCAL __MUL16LOOP LOCAL __MUL16NOADD - + ex de, hl pop hl ; Return address ex (sp), hl ; CALLEE caller convention - + ;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand ;; ld c, h ;; ld a, l ; C,A => 1st Operand @@ -107,44 +107,44 @@ __MUL16: ; Mutiplies HL with the last value stored into de stack ;;__MUL16NOADD: ;; sla e ;; rl d - ;; + ;; ;; djnz __MUL16LOOP - + __MUL16_FAST: ld b, 16 ld a, d ld c, e ex de, hl ld hl, 0 - + __MUL16LOOP: add hl, hl ; hl << 1 sla c rla ; a,c << 1 jp nc, __MUL16NOADD add hl, de - + __MUL16NOADD: djnz __MUL16LOOP - + ret ; Result in hl (16 lower bits) - + ENDP - + #line 20 "array.asm" - + #line 24 "/src/zxb/trunk/library-asm/array.asm" - + __ARRAY: PROC - + LOCAL LOOP LOCAL ARRAY_END LOCAL RET_ADDRESS ; Stores return address - + ex (sp), hl ; Return address in HL, array address in the stack ld (RET_ADDRESS + 1), hl ; Stores it for later - + exx pop hl ; Will use H'L' as the pointer ld c, (hl) ; Loads Number of dimensions from (hl) @@ -152,23 +152,23 @@ __ARRAY: ld b, (hl) inc hl ; Ready exx - + ld hl, 0 ; BC = Offset "accumulator" - + #line 48 "/src/zxb/trunk/library-asm/array.asm" - + LOOP: pop bc ; Get next index (Ai) from the stack - + #line 60 "/src/zxb/trunk/library-asm/array.asm" - + add hl, bc ; Adds current index - + exx ; Checks if B'C' = 0 ld a, b ; Which means we must exit (last element is not multiplied by anything) or c jr z, ARRAY_END ; if B'Ci == 0 we are done - + ld e, (hl) ; Loads next dimension into D'E' inc hl ld d, (hl) @@ -177,13 +177,13 @@ LOOP: dec bc ; Decrements loop counter exx pop de ; DE = Max bound Number (i-th dimension) - + #line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL #line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP - + ARRAY_END: ld e, (hl) inc hl @@ -191,75 +191,75 @@ ARRAY_END: push hl push de exx - + #line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP - + ex de, hl ld hl, 0 pop bc ld b, c -ARRAY_SIZE_LOOP: +ARRAY_SIZE_LOOP: add hl, de djnz ARRAY_SIZE_LOOP - + ;; Even faster ;pop bc - + ;ld d, h ;ld e, l - + ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;dec c ;jp z, __ARRAY_FIN - + ;add hl, de - ;__ARRAY_FIN: + ;__ARRAY_FIN: #line 131 "/src/zxb/trunk/library-asm/array.asm" - + pop de add hl, de ; Adds element start - + RET_ADDRESS: ld de, 0 push de ret ; HL = (Start of Elements + Offset) - + ;; Performs a faster multiply for little 16bit numbs LOCAL __FNMUL, __FNMUL2 - + __FNMUL: xor a or d jp nz, __MUL16_FAST - + or e ex de, hl ret z - + cp 33 jp nc, __MUL16_FAST - + ld b, l ld l, h ; HL = 0 - + __FNMUL2: add hl, de djnz __FNMUL2 ret - + ENDP - + #line 48 "ltee10.bas" - + ZXBASIC_USER_DATA: _pos: DEFB 00 diff --git a/tests/functional/ltee3.asm b/tests/functional/ltee3.asm index 0fc061c74..6a60a2631 100644 --- a/tests/functional/ltee3.asm +++ b/tests/functional/ltee3.asm @@ -63,10 +63,10 @@ __LABEL0: DEFB 6Eh DEFB 67h #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -74,25 +74,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -101,41 +101,41 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -143,25 +143,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -170,39 +170,39 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -210,56 +210,56 @@ __LABEL0: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -268,57 +268,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -327,47 +327,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -377,17 +377,17 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 51 "ltee3.bas" #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -395,25 +395,25 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -422,51 +422,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -474,12 +474,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -487,16 +487,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -508,27 +508,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -540,7 +540,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -548,15 +548,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -581,14 +581,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -596,25 +596,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -623,37 +623,37 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) pop hl ; Recovers destiny in hl as result ret #line 52 "ltee3.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/ltee4.asm b/tests/functional/ltee4.asm index e2a492db1..27f705c1c 100644 --- a/tests/functional/ltee4.asm +++ b/tests/functional/ltee4.asm @@ -40,7 +40,7 @@ _hsGetName__leave: ex (sp), hl exx ret - + ZXBASIC_USER_DATA: _hsName: DEFW 0000h diff --git a/tests/functional/ltee5.asm b/tests/functional/ltee5.asm index 052c83ab4..cc35f44c2 100644 --- a/tests/functional/ltee5.asm +++ b/tests/functional/ltee5.asm @@ -74,10 +74,10 @@ __LABEL1: DEFB 61h DEFB 6Ch #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -85,25 +85,25 @@ __LABEL1: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -112,41 +112,41 @@ __LABEL1: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -154,25 +154,25 @@ __LABEL1: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -181,39 +181,39 @@ __LABEL1: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -221,56 +221,56 @@ __LABEL1: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -279,57 +279,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -338,47 +338,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -388,20 +388,20 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 62 "ltee5.bas" #line 1 "pstorestr.asm" - + ; vim:ts=4:et:sw=4 - ; + ; ; Stores an string (pointer to the HEAP by DE) into the address pointed ; by (IX + BC). A new copy of the string is created into the HEAP ; - + #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -412,15 +412,15 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -428,25 +428,25 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -455,52 +455,52 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -508,12 +508,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -521,7 +521,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -529,10 +529,10 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -540,25 +540,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -567,40 +567,40 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - - + + + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -612,27 +612,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -644,7 +644,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -652,15 +652,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -685,14 +685,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -700,23 +700,23 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 71 "realloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -735,29 +735,29 @@ __MEM_SUBTRACT: ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -766,111 +766,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -886,7 +886,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -894,53 +894,53 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 8 "pstorestr.asm" - + __PSTORE_STR: push ix pop hl add hl, bc jp __STORE_STR - + #line 63 "ltee5.bas" - - + + ZXBASIC_USER_DATA: _testglobal: DEFB 00, 00 diff --git a/tests/functional/ltee6.asm b/tests/functional/ltee6.asm index 0888daed1..694c22b10 100644 --- a/tests/functional/ltee6.asm +++ b/tests/functional/ltee6.asm @@ -46,10 +46,10 @@ __LABEL0: DEFB 61h DEFB 6Ch #line 1 "array.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ------------------------------------------------------------------- ; Simple array Index routine @@ -57,28 +57,28 @@ __LABEL0: ; HL = Start of array memory (First two bytes contains N-1 dimensions) ; Dimension values on the stack, (top of the stack, highest dimension) ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> - + ; For any array of N dimension A(aN-1, ..., a1, a0) ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] ; What I will do here is to calculate the following sequence: ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... - - + + #line 1 "mul16.asm" - + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned - + PROC - + LOCAL __MUL16LOOP LOCAL __MUL16NOADD - + ex de, hl pop hl ; Return address ex (sp), hl ; CALLEE caller convention - + ;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand ;; ld c, h ;; ld a, l ; C,A => 1st Operand @@ -96,44 +96,44 @@ __MUL16: ; Mutiplies HL with the last value stored into de stack ;;__MUL16NOADD: ;; sla e ;; rl d - ;; + ;; ;; djnz __MUL16LOOP - + __MUL16_FAST: ld b, 16 ld a, d ld c, e ex de, hl ld hl, 0 - + __MUL16LOOP: add hl, hl ; hl << 1 sla c rla ; a,c << 1 jp nc, __MUL16NOADD add hl, de - + __MUL16NOADD: djnz __MUL16LOOP - + ret ; Result in hl (16 lower bits) - + ENDP - + #line 20 "array.asm" - + #line 24 "/src/zxb/trunk/library-asm/array.asm" - + __ARRAY: PROC - + LOCAL LOOP LOCAL ARRAY_END LOCAL RET_ADDRESS ; Stores return address - + ex (sp), hl ; Return address in HL, array address in the stack ld (RET_ADDRESS + 1), hl ; Stores it for later - + exx pop hl ; Will use H'L' as the pointer ld c, (hl) ; Loads Number of dimensions from (hl) @@ -141,23 +141,23 @@ __ARRAY: ld b, (hl) inc hl ; Ready exx - + ld hl, 0 ; BC = Offset "accumulator" - + #line 48 "/src/zxb/trunk/library-asm/array.asm" - + LOOP: pop bc ; Get next index (Ai) from the stack - + #line 60 "/src/zxb/trunk/library-asm/array.asm" - + add hl, bc ; Adds current index - + exx ; Checks if B'C' = 0 ld a, b ; Which means we must exit (last element is not multiplied by anything) or c jr z, ARRAY_END ; if B'Ci == 0 we are done - + ld e, (hl) ; Loads next dimension into D'E' inc hl ld d, (hl) @@ -166,13 +166,13 @@ LOOP: dec bc ; Decrements loop counter exx pop de ; DE = Max bound Number (i-th dimension) - + #line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL #line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP - + ARRAY_END: ld e, (hl) inc hl @@ -180,76 +180,76 @@ ARRAY_END: push hl push de exx - + #line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP - + ex de, hl ld hl, 0 pop bc ld b, c -ARRAY_SIZE_LOOP: +ARRAY_SIZE_LOOP: add hl, de djnz ARRAY_SIZE_LOOP - + ;; Even faster ;pop bc - + ;ld d, h ;ld e, l - + ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;dec c ;jp z, __ARRAY_FIN - + ;add hl, de - ;__ARRAY_FIN: + ;__ARRAY_FIN: #line 131 "/src/zxb/trunk/library-asm/array.asm" - + pop de add hl, de ; Adds element start - + RET_ADDRESS: ld de, 0 push de ret ; HL = (Start of Elements + Offset) - + ;; Performs a faster multiply for little 16bit numbs LOCAL __FNMUL, __FNMUL2 - + __FNMUL: xor a or d jp nz, __MUL16_FAST - + or e ex de, hl ret z - + cp 33 jp nc, __MUL16_FAST - + ld b, l ld l, h ; HL = 0 - + __FNMUL2: add hl, de djnz __FNMUL2 ret - + ENDP - + #line 34 "ltee6.bas" #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -260,15 +260,15 @@ __FNMUL2: ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -276,25 +276,25 @@ __FNMUL2: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -303,52 +303,52 @@ __FNMUL2: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -356,12 +356,12 @@ __FNMUL2: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -369,7 +369,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -377,10 +377,10 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -388,25 +388,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -415,42 +415,42 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -458,25 +458,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -485,39 +485,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -525,57 +525,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -587,27 +587,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -619,7 +619,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -627,15 +627,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -660,14 +660,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -675,25 +675,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 71 "realloc.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -701,25 +701,25 @@ __MEM_SUBTRACT: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -728,38 +728,38 @@ __MEM_SUBTRACT: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -768,57 +768,57 @@ __MEM_SUBTRACT: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -827,47 +827,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -877,12 +877,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 72 "realloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -901,29 +901,29 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -932,111 +932,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -1052,7 +1052,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -1060,44 +1060,44 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 35 "ltee6.bas" - + ZXBASIC_USER_DATA: _pos: DEFB 00 diff --git a/tests/functional/ltee7.asm b/tests/functional/ltee7.asm index 01786c658..cab0bbad4 100644 --- a/tests/functional/ltee7.asm +++ b/tests/functional/ltee7.asm @@ -84,10 +84,10 @@ __LABEL0: DEFB 6Ch DEFB 6Fh #line 1 "array.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ------------------------------------------------------------------- ; Simple array Index routine @@ -95,28 +95,28 @@ __LABEL0: ; HL = Start of array memory (First two bytes contains N-1 dimensions) ; Dimension values on the stack, (top of the stack, highest dimension) ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> - + ; For any array of N dimension A(aN-1, ..., a1, a0) ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] ; What I will do here is to calculate the following sequence: ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... - - + + #line 1 "mul16.asm" - + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned - + PROC - + LOCAL __MUL16LOOP LOCAL __MUL16NOADD - + ex de, hl pop hl ; Return address ex (sp), hl ; CALLEE caller convention - + ;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand ;; ld c, h ;; ld a, l ; C,A => 1st Operand @@ -134,44 +134,44 @@ __MUL16: ; Mutiplies HL with the last value stored into de stack ;;__MUL16NOADD: ;; sla e ;; rl d - ;; + ;; ;; djnz __MUL16LOOP - + __MUL16_FAST: ld b, 16 ld a, d ld c, e ex de, hl ld hl, 0 - + __MUL16LOOP: add hl, hl ; hl << 1 sla c rla ; a,c << 1 jp nc, __MUL16NOADD add hl, de - + __MUL16NOADD: djnz __MUL16LOOP - + ret ; Result in hl (16 lower bits) - + ENDP - + #line 20 "array.asm" - + #line 24 "/src/zxb/trunk/library-asm/array.asm" - + __ARRAY: PROC - + LOCAL LOOP LOCAL ARRAY_END LOCAL RET_ADDRESS ; Stores return address - + ex (sp), hl ; Return address in HL, array address in the stack ld (RET_ADDRESS + 1), hl ; Stores it for later - + exx pop hl ; Will use H'L' as the pointer ld c, (hl) ; Loads Number of dimensions from (hl) @@ -179,23 +179,23 @@ __ARRAY: ld b, (hl) inc hl ; Ready exx - + ld hl, 0 ; BC = Offset "accumulator" - + #line 48 "/src/zxb/trunk/library-asm/array.asm" - + LOOP: pop bc ; Get next index (Ai) from the stack - + #line 60 "/src/zxb/trunk/library-asm/array.asm" - + add hl, bc ; Adds current index - + exx ; Checks if B'C' = 0 ld a, b ; Which means we must exit (last element is not multiplied by anything) or c jr z, ARRAY_END ; if B'Ci == 0 we are done - + ld e, (hl) ; Loads next dimension into D'E' inc hl ld d, (hl) @@ -204,13 +204,13 @@ LOOP: dec bc ; Decrements loop counter exx pop de ; DE = Max bound Number (i-th dimension) - + #line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL #line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP - + ARRAY_END: ld e, (hl) inc hl @@ -218,85 +218,85 @@ ARRAY_END: push hl push de exx - + #line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP - + ex de, hl ld hl, 0 pop bc ld b, c -ARRAY_SIZE_LOOP: +ARRAY_SIZE_LOOP: add hl, de djnz ARRAY_SIZE_LOOP - + ;; Even faster ;pop bc - + ;ld d, h ;ld e, l - + ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;dec c ;jp z, __ARRAY_FIN - + ;add hl, de - ;__ARRAY_FIN: + ;__ARRAY_FIN: #line 131 "/src/zxb/trunk/library-asm/array.asm" - + pop de add hl, de ; Adds element start - + RET_ADDRESS: ld de, 0 push de ret ; HL = (Start of Elements + Offset) - + ;; Performs a faster multiply for little 16bit numbs LOCAL __FNMUL, __FNMUL2 - + __FNMUL: xor a or d jp nz, __MUL16_FAST - + or e ex de, hl ret z - + cp 33 jp nc, __MUL16_FAST - + ld b, l ld l, h ; HL = 0 - + __FNMUL2: add hl, de djnz __FNMUL2 ret - + ENDP - + #line 72 "ltee7.bas" #line 1 "arrayfree.asm" - + ; This routine is in charge of freeing an array of strings from memory ; HL = Pointer to start of array in memory ; Top of the stack = Number of elements of the array - + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -304,25 +304,25 @@ __FNMUL2: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -331,41 +331,41 @@ __FNMUL2: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -373,25 +373,25 @@ __FNMUL2: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -400,39 +400,39 @@ __FNMUL2: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -440,56 +440,56 @@ __FNMUL2: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -498,57 +498,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -557,47 +557,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -607,30 +607,30 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 6 "arrayfree.asm" - + __ARRAY_FREE: PROC - + LOCAL __ARRAY_LOOP - + ex de, hl pop hl ; (ret address) ex (sp), hl ; Callee -> HL = Number of elements - - ex de, hl - + + ex de, hl + __ARRAY_FREE_FAST: ; Fastcall entry: DE = Number of elements ld a, h or l ret z ; ret if NULL - + ld b, d ld c, e - + ld e, (hl) inc hl ld d, (hl) @@ -639,45 +639,45 @@ __ARRAY_FREE_FAST: ; Fastcall entry: DE = Number of elements add hl, hl ; HL = HL * 2 add hl, de inc hl ; HL now points to the element start - + __ARRAY_LOOP: ld e, (hl) inc hl ld d, (hl) inc hl ; DE = (HL) = String Pointer - + push hl push bc ex de, hl call __MEM_FREE ; Frees it from memory pop bc pop hl - + dec bc ld a, b or c jp nz, __ARRAY_LOOP - + ret ; Frees it and return - + ENDP - - + + __ARRAY_FREE_MEM: ; like the above, buf also frees the array itself ex de, hl pop hl ; (ret address) ex (sp), hl ; Callee -> HL = Number of elements - ex de, hl - + ex de, hl + push hl ; Saves array pointer for later call __ARRAY_FREE_FAST pop hl ; recovers array block pointer - + jp __MEM_FREE ; Frees it and returns from __MEM_FREE - + #line 73 "ltee7.bas" #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -688,15 +688,15 @@ __ARRAY_FREE_MEM: ; like the above, buf also frees the array itself ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -704,25 +704,25 @@ __ARRAY_FREE_MEM: ; like the above, buf also frees the array itself ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -731,52 +731,52 @@ __ARRAY_FREE_MEM: ; like the above, buf also frees the array itself ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -784,12 +784,12 @@ __ARRAY_FREE_MEM: ; like the above, buf also frees the array itself ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -797,7 +797,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -805,10 +805,10 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -816,25 +816,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -843,40 +843,40 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - - + + + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -888,27 +888,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -920,7 +920,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -928,15 +928,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -961,14 +961,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -976,23 +976,23 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 71 "realloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -1011,29 +1011,29 @@ __MEM_SUBTRACT: ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -1042,111 +1042,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -1162,7 +1162,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -1170,44 +1170,44 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 74 "ltee7.bas" - + ZXBASIC_USER_DATA: _pos: DEFB 00 diff --git a/tests/functional/ltee8.asm b/tests/functional/ltee8.asm index 53682cff8..56c0ecec1 100644 --- a/tests/functional/ltee8.asm +++ b/tests/functional/ltee8.asm @@ -28,7 +28,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/ltee9.asm b/tests/functional/ltee9.asm index adb919f96..42efe7f4f 100644 --- a/tests/functional/ltee9.asm +++ b/tests/functional/ltee9.asm @@ -94,17 +94,17 @@ _start__leave: pop ix ret #line 1 "div16.asm" - - ; 16 bit division and modulo functions + + ; 16 bit division and modulo functions ; for both signed and unsigned values - + #line 1 "neg16.asm" - + ; Negates HL value (16 bit) __ABS16: bit 7, h ret z - + __NEGHL: ld a, l ; HL = -HL cpl @@ -114,23 +114,23 @@ __NEGHL: ld h, a inc hl ret - + #line 5 "div16.asm" - + __DIVU16: ; 16 bit unsigned division ; HL = Dividend, Stack Top = Divisor - + ; -- OBSOLETE ; Now uses FASTCALL convention ; ex de, hl ; pop hl ; Return address ; ex (sp), hl ; CALLEE Convention - + __DIVU16_FAST: ld a, h ld c, l ld hl, 0 ld b, 16 - + __DIV16LOOP: sll c rla @@ -139,46 +139,46 @@ __DIV16LOOP: jr nc, __DIV16NOADD add hl,de dec c - + __DIV16NOADD: djnz __DIV16LOOP - + ex de, hl ld h, a ld l, c - + ret ; HL = quotient, DE = Mudulus - - - + + + __MODU16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVU16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - - + + __DIVI16: ; 16 bit signed division ; --- The following is OBSOLETE --- ; ex de, hl ; pop hl ; ex (sp), hl ; CALLEE Convention - + __DIVI16_FAST: ld a, d xor h ex af, af' ; BIT 7 of a contains result - + bit 7, d ; DE is negative? - jr z, __DIVI16A - + jr z, __DIVI16A + ld a, e ; DE = -DE cpl ld e, a @@ -186,45 +186,45 @@ __DIVI16_FAST: cpl ld d, a inc de - + __DIVI16A: bit 7, h ; HL is negative? call nz, __NEGHL - + __DIVI16B: call __DIVU16_FAST ex af, af' - - or a + + or a ret p ; return if positive jp __NEGHL - - + + __MODI16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVI16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - + #line 85 "ltee9.bas" #line 1 "mul32.asm" - + #line 1 "_mul32.asm" - - + + ; Ripped from: http://www.andreadrian.de/oldcpu/z80_number_cruncher.html#moztocid784223 ; Used with permission. ; Multiplies 32x32 bit integer (DEHL x D'E'H'L') ; 64bit result is returned in H'L'H L B'C'A C - - + + __MUL32_64START: push hl exx @@ -233,18 +233,18 @@ __MUL32_64START: pop hl ; HL = Load Part (B) ex de, hl ; DE = Low Part (B), HL = HightPart(A) (must be in B'C') push hl - + exx pop bc ; B'C' = HightPart(A) exx ; A = B'C'BC , B = D'E'DE - + ; multiply routine 32 * 32bit = 64bit ; h'l'hlb'c'ac = b'c'bc * d'e'de ; needs register a, changes flags ; ; this routine was with tiny differences in the ; sinclair zx81 rom for the mantissa multiply - + __LMUL: and a ; reset carry flag sbc hl,hl ; result bits 32..47 = 0 @@ -253,8 +253,8 @@ __LMUL: exx ld a,b ; mpr is b'c'ac ld b,33 ; initialize loop counter - jp __LMULSTART - + jp __LMULSTART + __LMULLOOP: jr nc,__LMULNOADD ; JP is 2 cycles faster than JR. Since it's inside a LOOP ; it can save up to 33 * 2 = 66 cycles @@ -263,7 +263,7 @@ __LMULLOOP: exx adc hl,de exx - + __LMULNOADD: exx rr h ; right shift upper @@ -271,7 +271,7 @@ __LMULNOADD: exx rr h rr l - + __LMULSTART: exx rr b ; right shift mpr/ @@ -280,11 +280,11 @@ __LMULSTART: rra ; equivalent to rr a rr c djnz __LMULLOOP - + ret ; result in h'l'hlb'c'ac - + #line 2 "mul32.asm" - + __MUL32: ; multiplies 32 bit un/signed integer. ; First operand stored in DEHL, and 2nd onto stack ; Lowest part of 2nd operand on top of the stack @@ -295,7 +295,7 @@ __MUL32: ; multiplies 32 bit un/signed integer. ex (sp), hl ; CALLEE -> HL = High part ex de, hl call __MUL32_64START - + __TO32BIT: ; Converts H'L'HLB'C'AC to DEHL (Discards H'L'HL) exx push bc @@ -304,26 +304,26 @@ __TO32BIT: ; Converts H'L'HLB'C'AC to DEHL (Discards H'L'HL) ld h, a ld l, c ret - - + + #line 86 "ltee9.bas" #line 1 "pstore32.asm" - + #line 1 "store32.asm" - + __PISTORE32: push hl push ix pop hl add hl, bc pop bc - + __ISTORE32: ; Load address at hl, and stores E,D,B,C integer at that address ld a, (hl) inc hl ld h, (hl) ld l, a - + __STORE32: ; Stores the given integer in DEBC at address HL ld (hl), c inc hl @@ -333,9 +333,9 @@ __STORE32: ; Stores the given integer in DEBC at address HL inc hl ld (hl), d ret - + #line 2 "pstore32.asm" - + ; Stores a 32 bit integer number (DE,HL) at (IX + BC) __PSTORE32: push hl @@ -346,36 +346,36 @@ __PSTORE32: jp __STORE32 #line 87 "ltee9.bas" #line 1 "sub32.asm" - - ; SUB32 + + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) ; and returns result in DEHL. Carry an Z are set correctly - + __SUB32: exx pop bc ; saves return address in BC' exx - + or a ; clears carry flag ld b, h ; Operands come reversed => BC <- HL, HL = HL - BC ld c, l pop hl sbc hl, bc ex de, hl - + ld b, h ; High part (DE) now in HL. Repeat operation ld c, l pop hl sbc hl, bc ex de, hl ; DEHL now has de 32 bit result - + exx push bc ; puts return address back exx ret #line 88 "ltee9.bas" - + ZXBASIC_USER_DATA: _x: DEFB 00, 00 diff --git a/tests/functional/ltf16.asm b/tests/functional/ltf16.asm index 171491c3c..4d2079315 100644 --- a/tests/functional/ltf16.asm +++ b/tests/functional/ltf16.asm @@ -84,52 +84,52 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "lti32.asm" - - + + #line 1 "sub32.asm" - - ; SUB32 + + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) ; and returns result in DEHL. Carry an Z are set correctly - + __SUB32: exx pop bc ; saves return address in BC' exx - + or a ; clears carry flag ld b, h ; Operands come reversed => BC <- HL, HL = HL - BC ld c, l pop hl sbc hl, bc ex de, hl - + ld b, h ; High part (DE) now in HL. Repeat operation ld c, l pop hl sbc hl, bc ex de, hl ; DEHL now has de 32 bit result - + exx push bc ; puts return address back exx ret #line 3 "lti32.asm" - + __LTI32: ; Test 32 bit values in Top of the stack < HLDE PROC LOCAL checkParity exx pop de ; Preserves return address exx - + call __SUB32 - + exx push de ; Restores return address exx - + jp po, checkParity ld a, d xor 0x80 @@ -141,10 +141,10 @@ checkParity: ENDP #line 75 "ltf16.bas" #line 1 "swap32.asm" - + ; Exchanges current DE HL with the ; ones in the stack - + __SWAP32: pop bc ; Return address ex (sp), hl @@ -157,9 +157,9 @@ __SWAP32: inc sp push bc ret - + #line 76 "ltf16.bas" - + ZXBASIC_USER_DATA: _level: DEFB 00h diff --git a/tests/functional/lti32c.asm b/tests/functional/lti32c.asm index e3906c743..0e4a27827 100644 --- a/tests/functional/lti32c.asm +++ b/tests/functional/lti32c.asm @@ -97,52 +97,52 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "lti32.asm" - - + + #line 1 "sub32.asm" - - ; SUB32 + + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) ; and returns result in DEHL. Carry an Z are set correctly - + __SUB32: exx pop bc ; saves return address in BC' exx - + or a ; clears carry flag ld b, h ; Operands come reversed => BC <- HL, HL = HL - BC ld c, l pop hl sbc hl, bc ex de, hl - + ld b, h ; High part (DE) now in HL. Repeat operation ld c, l pop hl sbc hl, bc ex de, hl ; DEHL now has de 32 bit result - + exx push bc ; puts return address back exx ret #line 3 "lti32.asm" - + __LTI32: ; Test 32 bit values in Top of the stack < HLDE PROC LOCAL checkParity exx pop de ; Preserves return address exx - + call __SUB32 - + exx push de ; Restores return address exx - + jp po, checkParity ld a, d xor 0x80 @@ -154,10 +154,10 @@ checkParity: ENDP #line 88 "lti32c.bas" #line 1 "swap32.asm" - + ; Exchanges current DE HL with the ; ones in the stack - + __SWAP32: pop bc ; Return address ex (sp), hl @@ -170,9 +170,9 @@ __SWAP32: inc sp push bc ret - + #line 89 "lti32c.bas" - + ZXBASIC_USER_DATA: _level: DEFB 01h diff --git a/tests/functional/ltu32c.asm b/tests/functional/ltu32c.asm index 564f08585..47fec8bcb 100644 --- a/tests/functional/ltu32c.asm +++ b/tests/functional/ltu32c.asm @@ -102,40 +102,40 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sub32.asm" - - ; SUB32 + + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) ; and returns result in DEHL. Carry an Z are set correctly - + __SUB32: exx pop bc ; saves return address in BC' exx - + or a ; clears carry flag ld b, h ; Operands come reversed => BC <- HL, HL = HL - BC ld c, l pop hl sbc hl, bc ex de, hl - + ld b, h ; High part (DE) now in HL. Repeat operation ld c, l pop hl sbc hl, bc ex de, hl ; DEHL now has de 32 bit result - + exx push bc ; puts return address back exx ret #line 93 "ltu32c.bas" #line 1 "swap32.asm" - + ; Exchanges current DE HL with the ; ones in the stack - + __SWAP32: pop bc ; Return address ex (sp), hl @@ -148,9 +148,9 @@ __SWAP32: inc sp push bc ret - + #line 94 "ltu32c.bas" - + ZXBASIC_USER_DATA: _level: DEFB 01h diff --git a/tests/functional/mcleod.asm b/tests/functional/mcleod.asm index 4b9ab25a8..fc38a8078 100644 --- a/tests/functional/mcleod.asm +++ b/tests/functional/mcleod.asm @@ -38,52 +38,52 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "ftou32reg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "ftou32reg.asm" - + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) PROC - + LOCAL __IS_FLOAT - + or a - jr nz, __IS_FLOAT + jr nz, __IS_FLOAT ; Here if it is a ZX ROM Integer - + ld h, c ld l, d ld a, e ; Takes sign: FF = -, 0 = + @@ -91,98 +91,98 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS inc a jp z, __NEG32 ; Negates if negative ret - + __IS_FLOAT: ; Jumps here if it is a true floating point number - ld h, e + ld h, e push hl ; Stores it for later (Contains Sign in H) - + push de push bc - + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + ;ld a, c ; Get exponent sub 128 ; Exponent -= 128 jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 - + __FTOU32REG_LOOP: exx ; Shift C'B' E'D' << 1, output bit stays in Carry sla d rl e rl b rl c - + exx ; Shift DEHL << 1, inserting the carry on the right rl l rl h rl e rl d - + djnz __FTOU32REG_LOOP - + __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative jp m, __NEG32 ; Negates DEHL - + ret - + ENDP - - + + __FTOU8: ; Converts float in C ED LH to Unsigned byte in A call __FTOU32REG ld a, l ret - + #line 29 "mcleod.bas" #line 1 "mulf.asm" - + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -198,7 +198,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 2 "mulf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) ; All of them uses A EDCB registers as 1st paramter. @@ -207,40 +207,40 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; ; Uses CALLEE convention ; ------------------------------------------------------------- - + __MULF: ; Multiplication call __FPSTACK_PUSH2 - + ; ------------- ROM MUL rst 28h - defb 04h ; + defb 04h ; defb 38h; ; END CALC - + jp __FPSTACK_POP - + #line 30 "mcleod.bas" #line 1 "random.asm" - + ; RANDOM functions - + RANDOMIZE: ; Randomize with 32 bit seed in DE HL ; if SEED = 0, calls ROM to take frames as seed PROC - + LOCAL TAKE_FRAMES LOCAL FRAMES - + ld a, h or l or d or e jr z, TAKE_FRAMES - + ld (RANDOM_SEED_LOW), hl ld (RANDOM_SEED_HIGH), de ret - + TAKE_FRAMES: ; Takes the seed from frames ld hl, (FRAMES) @@ -248,18 +248,18 @@ TAKE_FRAMES: ld hl, (FRAMES + 2) ld (RANDOM_SEED_HIGH), hl ret - + FRAMES EQU 23672 ENDP - + RANDOM_SEED_HIGH EQU RAND+6 ; RANDOM seed, 16 higher bits RANDOM_SEED_LOW EQU 23670 ; RANDOM seed, 16 lower bits - - + + RAND: PROC LOCAL RAND_LOOP - ld b, 4 + ld b, 4 RAND_LOOP: ld hl,(RANDOM_SEED_LOW) ; xz -> yw ld de,0C0DEh ; yw -> zt @@ -291,30 +291,30 @@ RAND_LOOP: ld h, a ret ENDP - + RND: ; Returns a FLOATING point integer ; using RAND as a mantissa PROC LOCAL RND_LOOP - + call RAND ; BC = HL since ZX BASIC uses ED CB A registers for FP ld b, h ld c, l - + ld a, e or d or c or b ret z ; Returns 0 if BC=DE=0 - + ; We already have a random 32 bit mantissa in ED CB ; From 0001h to FFFFh - + ld l, 81h ; Exponent ; At this point we have [0 .. 1) FP number; - + ; Now we must shift mantissa left until highest bit goes into carry ld a, e ; Use A register for rotating E faster (using RLA instead of RL E) RND_LOOP: @@ -324,22 +324,22 @@ RND_LOOP: rl d rla jp nc, RND_LOOP - + ; Now undo last mantissa left-shift once ccf ; Clears carry to insert a 0 bit back into mantissa -> positive FP number rra - rr d + rr d rr c rr b - + ld e, a ; E must have the highest byte ld a, l ; exponent in A ret - + ENDP - + #line 31 "mcleod.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00 diff --git a/tests/functional/mcleod2.asm b/tests/functional/mcleod2.asm index d2fd41b24..c19bf3ca4 100644 --- a/tests/functional/mcleod2.asm +++ b/tests/functional/mcleod2.asm @@ -35,7 +35,7 @@ __CALL_BACK__: __LABEL0: DEFW 0000h #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -46,15 +46,15 @@ __LABEL0: ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -62,25 +62,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -89,52 +89,52 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -142,12 +142,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -155,7 +155,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -163,10 +163,10 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -174,25 +174,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -201,42 +201,42 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -244,25 +244,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -271,39 +271,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -311,57 +311,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -373,27 +373,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -405,7 +405,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -413,15 +413,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -446,14 +446,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -461,25 +461,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 71 "realloc.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -487,25 +487,25 @@ __MEM_SUBTRACT: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -514,38 +514,38 @@ __MEM_SUBTRACT: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -554,57 +554,57 @@ __MEM_SUBTRACT: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -613,47 +613,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -663,12 +663,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 72 "realloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -687,29 +687,29 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -718,111 +718,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -838,7 +838,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -846,44 +846,44 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 23 "mcleod2.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/modf16.asm b/tests/functional/modf16.asm index 5c2e29772..263451ce7 100644 --- a/tests/functional/modf16.asm +++ b/tests/functional/modf16.asm @@ -33,7 +33,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00 diff --git a/tests/functional/modf16c.asm b/tests/functional/modf16c.asm index 75c10937d..29c035267 100644 --- a/tests/functional/modf16c.asm +++ b/tests/functional/modf16c.asm @@ -77,47 +77,47 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "modf16.asm" - + ; Computes A % B for fixed values - + #line 1 "divf16.asm" - + #line 1 "div32.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "div32.asm" - + ; --------------------------------------------------------- __DIVU32: ; 32 bit unsigned division ; DEHL = Dividend, Stack Top = Divisor @@ -129,7 +129,7 @@ __DIVU32: ; 32 bit unsigned division pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + __DIVU32START: ; Performs D'E'H'L' / HLDE ; Now switch to DIVIDEND = B'C'BC / DIVISOR = D'E'DE (A / B) push de ; push Lowpart(Q) @@ -145,9 +145,9 @@ __DIVU32START: ; Performs D'E'H'L' / HLDE exx pop bc ; Pop HightPart(B) => B = B'C'BC exx - + ld a, 32 ; Loop count - + __DIV32LOOP: sll c ; B'C'BC << 1 ; Output most left bit to carry rl b @@ -155,29 +155,29 @@ __DIV32LOOP: rl c rl b exx - + adc hl, hl exx adc hl, hl exx - + sbc hl,de exx sbc hl,de exx jp nc, __DIV32NOADD ; use JP inside a loop for being faster - + add hl, de exx adc hl, de exx dec bc - + __DIV32NOADD: dec a jp nz, __DIV32LOOP ; use JP inside a loop for being faster ; At this point, quotient is stored in B'C'BC and the reminder in H'L'HL - + push hl exx pop de @@ -187,34 +187,34 @@ __DIV32NOADD: pop de ; DE = B'C' ld h, b ld l, c ; DEHL = quotient D'E'H'L' = Modulus - + ret ; DEHL = quotient, D'E'H'L' = Modulus - - - + + + __MODU32: ; 32 bit modulus for 32bit unsigned division ; DEHL = Dividend, Stack Top = Divisor (DE, HL) - + exx pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + call __DIVU32START ; At return, modulus is at D'E'H'L' - + __MODU32START: - + exx push de push hl - - exx + + exx pop hl pop de - + ret - - + + __DIVI32: ; 32 bit signed division ; DEHL = Dividend, Stack Top = Divisor ; A = Dividend, B = Divisor => A / B @@ -222,137 +222,137 @@ __DIVI32: ; 32 bit signed division pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + __DIVI32START: exx ld a, d ; Save sign ex af, af' bit 7, d ; Negative? call nz, __NEG32 ; Negates DEHL - + exx ; Now works with H'L'D'E' ex af, af' xor h ex af, af' ; Stores sign of the result for later - + bit 7, h ; Negative? ex de, hl ; HLDE = DEHL call nz, __NEG32 - ex de, hl - + ex de, hl + call __DIVU32START ex af, af' ; Recovers sign and 128 ; positive? ret z - + jp __NEG32 ; Negates DEHL and returns from there - - + + __MODI32: ; 32bits signed division modulus exx pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + call __DIVI32START - jp __MODU32START - + jp __MODU32START + #line 2 "divf16.asm" - - -__DIVF16: ; 16.16 Fixed point Division (signed) - - ; DE.HL = Dividend, Stack Top = Divisor - ; A = Dividend, B = Divisor => A / B - exx - pop hl ; return address - pop de ; low part - ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - ex de, hl ; D'E'.H'L' Dividend - -__DIVF16START: ; FAST Entry: DEHL => Dividend, D'E'H'L' => Divisor - ld a, d ; Save sign - ex af, af' - bit 7, d ; Negative? - call nz, __NEG32 ; Negates DEHL - - exx ; Now works with D'E'.H'L' - ex af, af' - xor d - ex af, af' ; Stores sign of the result for later - - bit 7, d ; Negative? - call nz, __NEG32 - exx ; Now we have DE.HL => Dividend - - ld b, 16 - -__SHIFTALOOP: ; Tries to shift Dividend to the left - bit 7, d - jp nz, __SHIFTB - add hl, hl - ex de, hl - adc hl, hl - ex de, hl - djnz __SHIFTALOOP - jp __DOF16_DIVRDY - -__SHIFTB: ; Cannot shift Dividend more to the left, try to shift Divisor to the right - ld a, b - exx - ld b, a - ; Divisor is in DEHL -__SHIFTBLOOP: - bit 1, l - jp nz, __DOF16_DIVIDE - sra d - rr e - rr h - rr l - djnz __SHIFTBLOOP - -__DOF16_DIVIDE: - ld a, b - exx - ld b, a - -__DOF16_DIVRDY: - exx - ex de, hl - push bc - call __DIVU32START - pop bc - - xor a - or b - jp z, __ENDF16DIV - -__SHIFTCLOOP: - add hl, hl ; Shift DECIMAL PART << 1 - ex de, hl - adc hl, hl ; Shift INTEGER PART << 1 Plus Carry - ex de, hl - djnz __SHIFTCLOOP - -__ENDF16DIV: ; Put the sign on the result - ex af, af' ; Recovers sign - and 128 ; positive? - ret z - jp __NEG32 ; Negates DEHL and returns from there - + + +__DIVF16: ; 16.16 Fixed point Division (signed) + + ; DE.HL = Dividend, Stack Top = Divisor + ; A = Dividend, B = Divisor => A / B + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + ex de, hl ; D'E'.H'L' Dividend + +__DIVF16START: ; FAST Entry: DEHL => Dividend, D'E'H'L' => Divisor + ld a, d ; Save sign + ex af, af' + bit 7, d ; Negative? + call nz, __NEG32 ; Negates DEHL + + exx ; Now works with D'E'.H'L' + ex af, af' + xor d + ex af, af' ; Stores sign of the result for later + + bit 7, d ; Negative? + call nz, __NEG32 + exx ; Now we have DE.HL => Dividend + + ld b, 16 + +__SHIFTALOOP: ; Tries to shift Dividend to the left + bit 7, d + jp nz, __SHIFTB + add hl, hl + ex de, hl + adc hl, hl + ex de, hl + djnz __SHIFTALOOP + jp __DOF16_DIVRDY + +__SHIFTB: ; Cannot shift Dividend more to the left, try to shift Divisor to the right + ld a, b + exx + ld b, a + ; Divisor is in DEHL +__SHIFTBLOOP: + bit 1, l + jp nz, __DOF16_DIVIDE + sra d + rr e + rr h + rr l + djnz __SHIFTBLOOP + +__DOF16_DIVIDE: + ld a, b + exx + ld b, a + +__DOF16_DIVRDY: + exx + ex de, hl + push bc + call __DIVU32START + pop bc + + xor a + or b + jp z, __ENDF16DIV + +__SHIFTCLOOP: + add hl, hl ; Shift DECIMAL PART << 1 + ex de, hl + adc hl, hl ; Shift INTEGER PART << 1 Plus Carry + ex de, hl + djnz __SHIFTCLOOP + +__ENDF16DIV: ; Put the sign on the result + ex af, af' ; Recovers sign + and 128 ; positive? + ret z + jp __NEG32 ; Negates DEHL and returns from there + #line 4 "modf16.asm" #line 1 "mulf16.asm" - - + + #line 1 "_mul32.asm" - - + + ; Ripped from: http://www.andreadrian.de/oldcpu/z80_number_cruncher.html#moztocid784223 ; Used with permission. ; Multiplies 32x32 bit integer (DEHL x D'E'H'L') ; 64bit result is returned in H'L'H L B'C'A C - - + + __MUL32_64START: push hl exx @@ -361,18 +361,18 @@ __MUL32_64START: pop hl ; HL = Load Part (B) ex de, hl ; DE = Low Part (B), HL = HightPart(A) (must be in B'C') push hl - + exx pop bc ; B'C' = HightPart(A) exx ; A = B'C'BC , B = D'E'DE - + ; multiply routine 32 * 32bit = 64bit ; h'l'hlb'c'ac = b'c'bc * d'e'de ; needs register a, changes flags ; ; this routine was with tiny differences in the ; sinclair zx81 rom for the mantissa multiply - + __LMUL: and a ; reset carry flag sbc hl,hl ; result bits 32..47 = 0 @@ -381,8 +381,8 @@ __LMUL: exx ld a,b ; mpr is b'c'ac ld b,33 ; initialize loop counter - jp __LMULSTART - + jp __LMULSTART + __LMULLOOP: jr nc,__LMULNOADD ; JP is 2 cycles faster than JR. Since it's inside a LOOP ; it can save up to 33 * 2 = 66 cycles @@ -391,7 +391,7 @@ __LMULLOOP: exx adc hl,de exx - + __LMULNOADD: exx rr h ; right shift upper @@ -399,7 +399,7 @@ __LMULNOADD: exx rr h rr l - + __LMULSTART: exx rr b ; right shift mpr/ @@ -408,29 +408,29 @@ __LMULSTART: rra ; equivalent to rr a rr c djnz __LMULLOOP - + ret ; result in h'l'hlb'c'ac - + #line 3 "mulf16.asm" - -__MULF16: ; + +__MULF16: ; ld a, d ; load sgn into a ex af, af' ; saves it call __ABS32 ; convert to positive - - exx + + exx pop hl ; Return address pop de ; Low part ex (sp), hl ; CALLEE caller convention; Now HL = Hight part, (SP) = Return address ex de, hl ; D'E' = High part (B), H'L' = Low part (B) (must be in DE) - + ex af, af' xor d ; A register contains resulting sgn ex af, af' call __ABS32 ; convert to positive - + call __MUL32_64START - + ; rounding (was not included in zx81) __ROUND_FIX: ; rounds a 64bit (32.32) fixed point number to 16.16 ; result returned in dehl @@ -440,59 +440,59 @@ __ROUND_FIX: ; rounds a 64bit (32.32) fixed point number to 16.16 ld hl,0 ; ld does not change carry adc hl,bc ; hl = hl + 0 + carry push hl - + exx ld bc,0 - adc hl,bc ; hl = hl + 0 + carry + adc hl,bc ; hl = hl + 0 + carry ex de, hl pop hl ; rounded result in de.hl - + ex af, af' ; recovers result sign or a jp m, __NEG32 ; if negative, negates it - - ret - + + ret + #line 5 "modf16.asm" - + __MODF16: ; 16.16 Fixed point Division (signed) ; DE.HL = Divisor, Stack Top = Divider ; A = Dividend, B = Divisor => A % B - + PROC LOCAL TEMP - + TEMP EQU 23698 ; MEMBOT - + pop bc ; ret addr ld (TEMP), bc ; stores it on MEMBOT temporarily - ld (TEMP + 2), hl ; stores HP of divider + ld (TEMP + 2), hl ; stores HP of divider ld (TEMP + 4), de ; stores DE of divider - + call __DIVF16 rlc d ; Sign into carry sbc a, a ; a register = -1 sgn(DE), or 0 ld d, a ld e, a ; DE = 0 if it was positive or 0; -1 if it was negative - + ld bc, (TEMP + 4) ; Pushes original divider into the stack push bc ld bc, (TEMP + 2) push bc - + ld bc, (TEMP) ; recovers return address push bc jp __MULF16 ; multiplies and return from there - + ENDP - + #line 68 "modf16c.bas" #line 1 "swap32.asm" - + ; Exchanges current DE HL with the ; ones in the stack - + __SWAP32: pop bc ; Return address ex (sp), hl @@ -505,9 +505,9 @@ __SWAP32: inc sp push bc ret - + #line 69 "modf16c.bas" - + ZXBASIC_USER_DATA: _level: DEFB 00h diff --git a/tests/functional/modi32c.asm b/tests/functional/modi32c.asm index 17478b430..e1ec47da1 100644 --- a/tests/functional/modi32c.asm +++ b/tests/functional/modi32c.asm @@ -80,41 +80,41 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div32.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "div32.asm" - + ; --------------------------------------------------------- __DIVU32: ; 32 bit unsigned division ; DEHL = Dividend, Stack Top = Divisor @@ -126,7 +126,7 @@ __DIVU32: ; 32 bit unsigned division pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + __DIVU32START: ; Performs D'E'H'L' / HLDE ; Now switch to DIVIDEND = B'C'BC / DIVISOR = D'E'DE (A / B) push de ; push Lowpart(Q) @@ -142,9 +142,9 @@ __DIVU32START: ; Performs D'E'H'L' / HLDE exx pop bc ; Pop HightPart(B) => B = B'C'BC exx - + ld a, 32 ; Loop count - + __DIV32LOOP: sll c ; B'C'BC << 1 ; Output most left bit to carry rl b @@ -152,29 +152,29 @@ __DIV32LOOP: rl c rl b exx - + adc hl, hl exx adc hl, hl exx - + sbc hl,de exx sbc hl,de exx jp nc, __DIV32NOADD ; use JP inside a loop for being faster - + add hl, de exx adc hl, de exx dec bc - + __DIV32NOADD: dec a jp nz, __DIV32LOOP ; use JP inside a loop for being faster ; At this point, quotient is stored in B'C'BC and the reminder in H'L'HL - + push hl exx pop de @@ -184,34 +184,34 @@ __DIV32NOADD: pop de ; DE = B'C' ld h, b ld l, c ; DEHL = quotient D'E'H'L' = Modulus - + ret ; DEHL = quotient, D'E'H'L' = Modulus - - - + + + __MODU32: ; 32 bit modulus for 32bit unsigned division ; DEHL = Dividend, Stack Top = Divisor (DE, HL) - + exx pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + call __DIVU32START ; At return, modulus is at D'E'H'L' - + __MODU32START: - + exx push de push hl - - exx + + exx pop hl pop de - + ret - - + + __DIVI32: ; 32 bit signed division ; DEHL = Dividend, Stack Top = Divisor ; A = Dividend, B = Divisor => A / B @@ -219,47 +219,47 @@ __DIVI32: ; 32 bit signed division pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + __DIVI32START: exx ld a, d ; Save sign ex af, af' bit 7, d ; Negative? call nz, __NEG32 ; Negates DEHL - + exx ; Now works with H'L'D'E' ex af, af' xor h ex af, af' ; Stores sign of the result for later - + bit 7, h ; Negative? ex de, hl ; HLDE = DEHL call nz, __NEG32 - ex de, hl - + ex de, hl + call __DIVU32START ex af, af' ; Recovers sign and 128 ; positive? ret z - + jp __NEG32 ; Negates DEHL and returns from there - - + + __MODI32: ; 32bits signed division modulus exx pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + call __DIVI32START - jp __MODU32START - + jp __MODU32START + #line 71 "modi32c.bas" #line 1 "swap32.asm" - + ; Exchanges current DE HL with the ; ones in the stack - + __SWAP32: pop bc ; Return address ex (sp), hl @@ -272,9 +272,9 @@ __SWAP32: inc sp push bc ret - + #line 72 "modi32c.bas" - + ZXBASIC_USER_DATA: _level: DEFB 01h diff --git a/tests/functional/modi8.asm b/tests/functional/modi8.asm index 82f98a1e9..2559c3d42 100644 --- a/tests/functional/modi8.asm +++ b/tests/functional/modi8.asm @@ -53,50 +53,50 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div8.asm" - + ; -------------------------------- -__DIVU8: ; 8 bit unsigned integer division +__DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A pop hl ; -------------------------------- ex (sp), hl ; CALLEE - + __DIVU8_FAST: ; Does A / H ld l, h ld h, a ; At this point do H / L - + ld b, 8 xor a ; A = 0, Carry Flag = 0 - + __DIV8LOOP: - sla h - rla - cp l + sla h + rla + cp l jr c, __DIV8NOSUB - sub l - inc h - -__DIV8NOSUB: + sub l + inc h + +__DIV8NOSUB: djnz __DIV8LOOP - + ld l, a ; save remainder - ld a, h ; - - ret ; a = Quotient, - - + ld a, h ; + + ret ; a = Quotient, + + ; -------------------------------- __DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A pop hl ; -------------------------------- ex (sp), hl - + __DIVI8_FAST: ld e, a ; store operands for later ld c, h - + or a ; negative? jp p, __DIV8A neg ; Make it positive - + __DIV8A: ex af, af' ld a, h @@ -104,45 +104,45 @@ __DIV8A: jp p, __DIV8B neg ld h, a ; make it positive - + __DIV8B: ex af, af' - + call __DIVU8_FAST - + ld a, c xor l ; bit 7 of A = 1 if result is negative - + ld a, h ; Quotient - ret p ; return if positive - + ret p ; return if positive + neg ret - - + + __MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) pop hl ex (sp), hl ; CALLEE - + __MODU8_FAST: ; __FASTCALL__ entry call __DIVU8_FAST ld a, l ; Remainder - + ret ; a = Modulus - - + + __MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) pop hl ex (sp), hl ; CALLEE - + __MODI8_FAST: ; __FASTCALL__ entry call __DIVI8_FAST ld a, l ; remainder - + ret ; a = Modulus - + #line 44 "modi8.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/modi8a.asm b/tests/functional/modi8a.asm index d7b577c98..35da3f652 100644 --- a/tests/functional/modi8a.asm +++ b/tests/functional/modi8a.asm @@ -33,50 +33,50 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div8.asm" - + ; -------------------------------- -__DIVU8: ; 8 bit unsigned integer division +__DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A pop hl ; -------------------------------- ex (sp), hl ; CALLEE - + __DIVU8_FAST: ; Does A / H ld l, h ld h, a ; At this point do H / L - + ld b, 8 xor a ; A = 0, Carry Flag = 0 - + __DIV8LOOP: - sla h - rla - cp l + sla h + rla + cp l jr c, __DIV8NOSUB - sub l - inc h - -__DIV8NOSUB: + sub l + inc h + +__DIV8NOSUB: djnz __DIV8LOOP - + ld l, a ; save remainder - ld a, h ; - - ret ; a = Quotient, - - + ld a, h ; + + ret ; a = Quotient, + + ; -------------------------------- __DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A pop hl ; -------------------------------- ex (sp), hl - + __DIVI8_FAST: ld e, a ; store operands for later ld c, h - + or a ; negative? jp p, __DIV8A neg ; Make it positive - + __DIV8A: ex af, af' ld a, h @@ -84,45 +84,45 @@ __DIV8A: jp p, __DIV8B neg ld h, a ; make it positive - + __DIV8B: ex af, af' - + call __DIVU8_FAST - + ld a, c xor l ; bit 7 of A = 1 if result is negative - + ld a, h ; Quotient - ret p ; return if positive - + ret p ; return if positive + neg ret - - + + __MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) pop hl ex (sp), hl ; CALLEE - + __MODU8_FAST: ; __FASTCALL__ entry call __DIVU8_FAST ld a, l ; Remainder - + ret ; a = Modulus - - + + __MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) pop hl ex (sp), hl ; CALLEE - + __MODI8_FAST: ; __FASTCALL__ entry call __DIVI8_FAST ld a, l ; remainder - + ret ; a = Modulus - + #line 24 "modi8a.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/modi8b.asm b/tests/functional/modi8b.asm index c30eeef68..35c4edf0c 100644 --- a/tests/functional/modi8b.asm +++ b/tests/functional/modi8b.asm @@ -39,50 +39,50 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div8.asm" - + ; -------------------------------- -__DIVU8: ; 8 bit unsigned integer division +__DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A pop hl ; -------------------------------- ex (sp), hl ; CALLEE - + __DIVU8_FAST: ; Does A / H ld l, h ld h, a ; At this point do H / L - + ld b, 8 xor a ; A = 0, Carry Flag = 0 - + __DIV8LOOP: - sla h - rla - cp l + sla h + rla + cp l jr c, __DIV8NOSUB - sub l - inc h - -__DIV8NOSUB: + sub l + inc h + +__DIV8NOSUB: djnz __DIV8LOOP - + ld l, a ; save remainder - ld a, h ; - - ret ; a = Quotient, - - + ld a, h ; + + ret ; a = Quotient, + + ; -------------------------------- __DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A pop hl ; -------------------------------- ex (sp), hl - + __DIVI8_FAST: ld e, a ; store operands for later ld c, h - + or a ; negative? jp p, __DIV8A neg ; Make it positive - + __DIV8A: ex af, af' ld a, h @@ -90,45 +90,45 @@ __DIV8A: jp p, __DIV8B neg ld h, a ; make it positive - + __DIV8B: ex af, af' - + call __DIVU8_FAST - + ld a, c xor l ; bit 7 of A = 1 if result is negative - + ld a, h ; Quotient - ret p ; return if positive - + ret p ; return if positive + neg ret - - + + __MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) pop hl ex (sp), hl ; CALLEE - + __MODU8_FAST: ; __FASTCALL__ entry call __DIVU8_FAST ld a, l ; Remainder - + ret ; a = Modulus - - + + __MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) pop hl ex (sp), hl ; CALLEE - + __MODI8_FAST: ; __FASTCALL__ entry call __DIVI8_FAST ld a, l ; remainder - + ret ; a = Modulus - + #line 30 "modi8b.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/modu32c.asm b/tests/functional/modu32c.asm index 40fa4a6ac..b8d0f1cd0 100644 --- a/tests/functional/modu32c.asm +++ b/tests/functional/modu32c.asm @@ -80,41 +80,41 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div32.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "div32.asm" - + ; --------------------------------------------------------- __DIVU32: ; 32 bit unsigned division ; DEHL = Dividend, Stack Top = Divisor @@ -126,7 +126,7 @@ __DIVU32: ; 32 bit unsigned division pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + __DIVU32START: ; Performs D'E'H'L' / HLDE ; Now switch to DIVIDEND = B'C'BC / DIVISOR = D'E'DE (A / B) push de ; push Lowpart(Q) @@ -142,9 +142,9 @@ __DIVU32START: ; Performs D'E'H'L' / HLDE exx pop bc ; Pop HightPart(B) => B = B'C'BC exx - + ld a, 32 ; Loop count - + __DIV32LOOP: sll c ; B'C'BC << 1 ; Output most left bit to carry rl b @@ -152,29 +152,29 @@ __DIV32LOOP: rl c rl b exx - + adc hl, hl exx adc hl, hl exx - + sbc hl,de exx sbc hl,de exx jp nc, __DIV32NOADD ; use JP inside a loop for being faster - + add hl, de exx adc hl, de exx dec bc - + __DIV32NOADD: dec a jp nz, __DIV32LOOP ; use JP inside a loop for being faster ; At this point, quotient is stored in B'C'BC and the reminder in H'L'HL - + push hl exx pop de @@ -184,34 +184,34 @@ __DIV32NOADD: pop de ; DE = B'C' ld h, b ld l, c ; DEHL = quotient D'E'H'L' = Modulus - + ret ; DEHL = quotient, D'E'H'L' = Modulus - - - + + + __MODU32: ; 32 bit modulus for 32bit unsigned division ; DEHL = Dividend, Stack Top = Divisor (DE, HL) - + exx pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + call __DIVU32START ; At return, modulus is at D'E'H'L' - + __MODU32START: - + exx push de push hl - - exx + + exx pop hl pop de - + ret - - + + __DIVI32: ; 32 bit signed division ; DEHL = Dividend, Stack Top = Divisor ; A = Dividend, B = Divisor => A / B @@ -219,47 +219,47 @@ __DIVI32: ; 32 bit signed division pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + __DIVI32START: exx ld a, d ; Save sign ex af, af' bit 7, d ; Negative? call nz, __NEG32 ; Negates DEHL - + exx ; Now works with H'L'D'E' ex af, af' xor h ex af, af' ; Stores sign of the result for later - + bit 7, h ; Negative? ex de, hl ; HLDE = DEHL call nz, __NEG32 - ex de, hl - + ex de, hl + call __DIVU32START ex af, af' ; Recovers sign and 128 ; positive? ret z - + jp __NEG32 ; Negates DEHL and returns from there - - + + __MODI32: ; 32bits signed division modulus exx pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + call __DIVI32START - jp __MODU32START - + jp __MODU32START + #line 71 "modu32c.bas" #line 1 "swap32.asm" - + ; Exchanges current DE HL with the ; ones in the stack - + __SWAP32: pop bc ; Return address ex (sp), hl @@ -272,9 +272,9 @@ __SWAP32: inc sp push bc ret - + #line 72 "modu32c.bas" - + ZXBASIC_USER_DATA: _level: DEFB 01h diff --git a/tests/functional/modu8.asm b/tests/functional/modu8.asm index bce638da9..703bee1fe 100644 --- a/tests/functional/modu8.asm +++ b/tests/functional/modu8.asm @@ -53,50 +53,50 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div8.asm" - + ; -------------------------------- -__DIVU8: ; 8 bit unsigned integer division +__DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A pop hl ; -------------------------------- ex (sp), hl ; CALLEE - + __DIVU8_FAST: ; Does A / H ld l, h ld h, a ; At this point do H / L - + ld b, 8 xor a ; A = 0, Carry Flag = 0 - + __DIV8LOOP: - sla h - rla - cp l + sla h + rla + cp l jr c, __DIV8NOSUB - sub l - inc h - -__DIV8NOSUB: + sub l + inc h + +__DIV8NOSUB: djnz __DIV8LOOP - + ld l, a ; save remainder - ld a, h ; - - ret ; a = Quotient, - - + ld a, h ; + + ret ; a = Quotient, + + ; -------------------------------- __DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A pop hl ; -------------------------------- ex (sp), hl - + __DIVI8_FAST: ld e, a ; store operands for later ld c, h - + or a ; negative? jp p, __DIV8A neg ; Make it positive - + __DIV8A: ex af, af' ld a, h @@ -104,45 +104,45 @@ __DIV8A: jp p, __DIV8B neg ld h, a ; make it positive - + __DIV8B: ex af, af' - + call __DIVU8_FAST - + ld a, c xor l ; bit 7 of A = 1 if result is negative - + ld a, h ; Quotient - ret p ; return if positive - + ret p ; return if positive + neg ret - - + + __MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) pop hl ex (sp), hl ; CALLEE - + __MODU8_FAST: ; __FASTCALL__ entry call __DIVU8_FAST ld a, l ; Remainder - + ret ; a = Modulus - - + + __MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) pop hl ex (sp), hl ; CALLEE - + __MODI8_FAST: ; __FASTCALL__ entry call __DIVI8_FAST ld a, l ; remainder - + ret ; a = Modulus - + #line 44 "modu8.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/modu8a.asm b/tests/functional/modu8a.asm index 8c977e225..cf1ced74f 100644 --- a/tests/functional/modu8a.asm +++ b/tests/functional/modu8a.asm @@ -33,50 +33,50 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div8.asm" - + ; -------------------------------- -__DIVU8: ; 8 bit unsigned integer division +__DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A pop hl ; -------------------------------- ex (sp), hl ; CALLEE - + __DIVU8_FAST: ; Does A / H ld l, h ld h, a ; At this point do H / L - + ld b, 8 xor a ; A = 0, Carry Flag = 0 - + __DIV8LOOP: - sla h - rla - cp l + sla h + rla + cp l jr c, __DIV8NOSUB - sub l - inc h - -__DIV8NOSUB: + sub l + inc h + +__DIV8NOSUB: djnz __DIV8LOOP - + ld l, a ; save remainder - ld a, h ; - - ret ; a = Quotient, - - + ld a, h ; + + ret ; a = Quotient, + + ; -------------------------------- __DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A pop hl ; -------------------------------- ex (sp), hl - + __DIVI8_FAST: ld e, a ; store operands for later ld c, h - + or a ; negative? jp p, __DIV8A neg ; Make it positive - + __DIV8A: ex af, af' ld a, h @@ -84,45 +84,45 @@ __DIV8A: jp p, __DIV8B neg ld h, a ; make it positive - + __DIV8B: ex af, af' - + call __DIVU8_FAST - + ld a, c xor l ; bit 7 of A = 1 if result is negative - + ld a, h ; Quotient - ret p ; return if positive - + ret p ; return if positive + neg ret - - + + __MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) pop hl ex (sp), hl ; CALLEE - + __MODU8_FAST: ; __FASTCALL__ entry call __DIVU8_FAST ld a, l ; Remainder - + ret ; a = Modulus - - + + __MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) pop hl ex (sp), hl ; CALLEE - + __MODI8_FAST: ; __FASTCALL__ entry call __DIVI8_FAST ld a, l ; remainder - + ret ; a = Modulus - + #line 24 "modu8a.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/modu8b.asm b/tests/functional/modu8b.asm index 840936ba6..ea362d097 100644 --- a/tests/functional/modu8b.asm +++ b/tests/functional/modu8b.asm @@ -39,50 +39,50 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "div8.asm" - + ; -------------------------------- -__DIVU8: ; 8 bit unsigned integer division +__DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A pop hl ; -------------------------------- ex (sp), hl ; CALLEE - + __DIVU8_FAST: ; Does A / H ld l, h ld h, a ; At this point do H / L - + ld b, 8 xor a ; A = 0, Carry Flag = 0 - + __DIV8LOOP: - sla h - rla - cp l + sla h + rla + cp l jr c, __DIV8NOSUB - sub l - inc h - -__DIV8NOSUB: + sub l + inc h + +__DIV8NOSUB: djnz __DIV8LOOP - + ld l, a ; save remainder - ld a, h ; - - ret ; a = Quotient, - - + ld a, h ; + + ret ; a = Quotient, + + ; -------------------------------- __DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A pop hl ; -------------------------------- ex (sp), hl - + __DIVI8_FAST: ld e, a ; store operands for later ld c, h - + or a ; negative? jp p, __DIV8A neg ; Make it positive - + __DIV8A: ex af, af' ld a, h @@ -90,45 +90,45 @@ __DIV8A: jp p, __DIV8B neg ld h, a ; make it positive - + __DIV8B: ex af, af' - + call __DIVU8_FAST - + ld a, c xor l ; bit 7 of A = 1 if result is negative - + ld a, h ; Quotient - ret p ; return if positive - + ret p ; return if positive + neg ret - - + + __MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) pop hl ex (sp), hl ; CALLEE - + __MODU8_FAST: ; __FASTCALL__ entry call __DIVU8_FAST ld a, l ; Remainder - + ret ; a = Modulus - - + + __MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) pop hl ex (sp), hl ; CALLEE - + __MODI8_FAST: ; __FASTCALL__ entry call __DIVI8_FAST ld a, l ; remainder - + ret ; a = Modulus - + #line 30 "modu8b.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/mul16.asm b/tests/functional/mul16.asm index 6cf21e992..e96f2153e 100644 --- a/tests/functional/mul16.asm +++ b/tests/functional/mul16.asm @@ -39,19 +39,19 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "mul16.asm" - + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned - + PROC - + LOCAL __MUL16LOOP LOCAL __MUL16NOADD - + ex de, hl pop hl ; Return address ex (sp), hl ; CALLEE caller convention - + ;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand ;; ld c, h ;; ld a, l ; C,A => 1st Operand @@ -69,32 +69,32 @@ __MUL16: ; Mutiplies HL with the last value stored into de stack ;;__MUL16NOADD: ;; sla e ;; rl d - ;; + ;; ;; djnz __MUL16LOOP - + __MUL16_FAST: ld b, 16 ld a, d ld c, e ex de, hl ld hl, 0 - + __MUL16LOOP: add hl, hl ; hl << 1 sla c rla ; a,c << 1 jp nc, __MUL16NOADD add hl, de - + __MUL16NOADD: djnz __MUL16LOOP - + ret ; Result in hl (16 lower bits) - + ENDP - + #line 30 "mul16.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/mul16a.asm b/tests/functional/mul16a.asm index 6abc4feac..fb02a40c4 100644 --- a/tests/functional/mul16a.asm +++ b/tests/functional/mul16a.asm @@ -34,19 +34,19 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "mul16.asm" - + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned - + PROC - + LOCAL __MUL16LOOP LOCAL __MUL16NOADD - + ex de, hl pop hl ; Return address ex (sp), hl ; CALLEE caller convention - + ;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand ;; ld c, h ;; ld a, l ; C,A => 1st Operand @@ -64,32 +64,32 @@ __MUL16: ; Mutiplies HL with the last value stored into de stack ;;__MUL16NOADD: ;; sla e ;; rl d - ;; + ;; ;; djnz __MUL16LOOP - + __MUL16_FAST: ld b, 16 ld a, d ld c, e ex de, hl ld hl, 0 - + __MUL16LOOP: add hl, hl ; hl << 1 sla c rla ; a,c << 1 jp nc, __MUL16NOADD add hl, de - + __MUL16NOADD: djnz __MUL16LOOP - + ret ; Result in hl (16 lower bits) - + ENDP - + #line 25 "mul16a.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/mul16b.asm b/tests/functional/mul16b.asm index fb8c5c1d0..e47df00d6 100644 --- a/tests/functional/mul16b.asm +++ b/tests/functional/mul16b.asm @@ -40,19 +40,19 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "mul16.asm" - + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned - + PROC - + LOCAL __MUL16LOOP LOCAL __MUL16NOADD - + ex de, hl pop hl ; Return address ex (sp), hl ; CALLEE caller convention - + ;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand ;; ld c, h ;; ld a, l ; C,A => 1st Operand @@ -70,32 +70,32 @@ __MUL16: ; Mutiplies HL with the last value stored into de stack ;;__MUL16NOADD: ;; sla e ;; rl d - ;; + ;; ;; djnz __MUL16LOOP - + __MUL16_FAST: ld b, 16 ld a, d ld c, e ex de, hl ld hl, 0 - + __MUL16LOOP: add hl, hl ; hl << 1 sla c rla ; a,c << 1 jp nc, __MUL16NOADD add hl, de - + __MUL16NOADD: djnz __MUL16LOOP - + ret ; Result in hl (16 lower bits) - + ENDP - + #line 31 "mul16b.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/mul8.asm b/tests/functional/mul8.asm index b76fc3344..f05a242b2 100644 --- a/tests/functional/mul8.asm +++ b/tests/functional/mul8.asm @@ -55,23 +55,23 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "mul8.asm" - + __MUL8: ; Performs 8bit x 8bit multiplication PROC - + ;LOCAL __MUL8A LOCAL __MUL8LOOP LOCAL __MUL8B ; 1st operand (byte) in A, 2nd operand into the stack (AF) pop hl ; return address ex (sp), hl ; CALLE convention - + ;;__MUL8_FAST: ; __FASTCALL__ entry ;; ld e, a ;; ld d, 0 ;; ld l, d - ;; - ;; sla h + ;; + ;; sla h ;; jr nc, __MUL8A ;; ld l, e ;; @@ -88,27 +88,27 @@ __MUL8: ; Performs 8bit x 8bit multiplication ;; djnz __MUL8LOOP ;; ;; ld a, l ; result = A and HL (Truncate to lower 8 bits) - + __MUL8_FAST: ; __FASTCALL__ entry, a = a * h (8 bit mul) and Carry - + ld b, 8 ld l, a xor a - + __MUL8LOOP: add a, a ; a *= 2 sla l jp nc, __MUL8B add a, h - + __MUL8B: djnz __MUL8LOOP - + ret ; result = HL ENDP - + #line 46 "mul8.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/mul8a.asm b/tests/functional/mul8a.asm index 3d1bbfb3a..a537b927e 100644 --- a/tests/functional/mul8a.asm +++ b/tests/functional/mul8a.asm @@ -34,23 +34,23 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "mul8.asm" - + __MUL8: ; Performs 8bit x 8bit multiplication PROC - + ;LOCAL __MUL8A LOCAL __MUL8LOOP LOCAL __MUL8B ; 1st operand (byte) in A, 2nd operand into the stack (AF) pop hl ; return address ex (sp), hl ; CALLE convention - + ;;__MUL8_FAST: ; __FASTCALL__ entry ;; ld e, a ;; ld d, 0 ;; ld l, d - ;; - ;; sla h + ;; + ;; sla h ;; jr nc, __MUL8A ;; ld l, e ;; @@ -67,27 +67,27 @@ __MUL8: ; Performs 8bit x 8bit multiplication ;; djnz __MUL8LOOP ;; ;; ld a, l ; result = A and HL (Truncate to lower 8 bits) - + __MUL8_FAST: ; __FASTCALL__ entry, a = a * h (8 bit mul) and Carry - + ld b, 8 ld l, a xor a - + __MUL8LOOP: add a, a ; a *= 2 sla l jp nc, __MUL8B add a, h - + __MUL8B: djnz __MUL8LOOP - + ret ; result = HL ENDP - + #line 25 "mul8a.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/mul8b.asm b/tests/functional/mul8b.asm index 8bbe2ee80..d32936967 100644 --- a/tests/functional/mul8b.asm +++ b/tests/functional/mul8b.asm @@ -40,23 +40,23 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "mul8.asm" - + __MUL8: ; Performs 8bit x 8bit multiplication PROC - + ;LOCAL __MUL8A LOCAL __MUL8LOOP LOCAL __MUL8B ; 1st operand (byte) in A, 2nd operand into the stack (AF) pop hl ; return address ex (sp), hl ; CALLE convention - + ;;__MUL8_FAST: ; __FASTCALL__ entry ;; ld e, a ;; ld d, 0 ;; ld l, d - ;; - ;; sla h + ;; + ;; sla h ;; jr nc, __MUL8A ;; ld l, e ;; @@ -73,27 +73,27 @@ __MUL8: ; Performs 8bit x 8bit multiplication ;; djnz __MUL8LOOP ;; ;; ld a, l ; result = A and HL (Truncate to lower 8 bits) - + __MUL8_FAST: ; __FASTCALL__ entry, a = a * h (8 bit mul) and Carry - + ld b, 8 ld l, a xor a - + __MUL8LOOP: add a, a ; a *= 2 sla l jp nc, __MUL8B add a, h - + __MUL8B: djnz __MUL8LOOP - + ret ; result = HL ENDP - + #line 31 "mul8b.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/mulf00.asm b/tests/functional/mulf00.asm index 47ac6b8af..d2963f680 100644 --- a/tests/functional/mulf00.asm +++ b/tests/functional/mulf00.asm @@ -35,40 +35,40 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "mulf.asm" - + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -84,7 +84,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 2 "mulf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) ; All of them uses A EDCB registers as 1st paramter. @@ -93,26 +93,26 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; ; Uses CALLEE convention ; ------------------------------------------------------------- - + __MULF: ; Multiplication call __FPSTACK_PUSH2 - + ; ------------- ROM MUL rst 28h - defb 04h ; + defb 04h ; defb 38h; ; END CALC - + jp __FPSTACK_POP - + #line 26 "mulf00.bas" #line 1 "pushf.asm" - - - ; Routine to push Float pointed by HL + + + ; Routine to push Float pointed by HL ; Into the stack. Notice that the hl points to the last ; byte of the FP number. ; Uses H'L' B'C' and D'E' to preserve ABCDEHL registers - + __FP_PUSH_REV: push hl exx @@ -133,11 +133,11 @@ __FP_PUSH_REV: push bc ; Return Address exx ret - - + + #line 27 "mulf00.bas" #line 1 "storef.asm" - + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -145,7 +145,7 @@ __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory pop hl ; HL <- IX add hl, de ; HL <- IX + HL pop de - + __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register ex af, af' ld a, (hl) @@ -153,7 +153,7 @@ __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address ld h, (hl) ld l, a ; HL = (HL) ex af, af' - + __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), a inc hl @@ -165,9 +165,9 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL inc hl ld (hl), b ret - + #line 28 "mulf00.bas" - + ZXBASIC_USER_DATA: _a: DEFB 80h diff --git a/tests/functional/mulf01.asm b/tests/functional/mulf01.asm index 957fdd678..5a3b95e21 100644 --- a/tests/functional/mulf01.asm +++ b/tests/functional/mulf01.asm @@ -39,40 +39,40 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "mulf.asm" - + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -88,7 +88,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 2 "mulf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) ; All of them uses A EDCB registers as 1st paramter. @@ -97,20 +97,20 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; ; Uses CALLEE convention ; ------------------------------------------------------------- - + __MULF: ; Multiplication call __FPSTACK_PUSH2 - + ; ------------- ROM MUL rst 28h - defb 04h ; + defb 04h ; defb 38h; ; END CALC - + jp __FPSTACK_POP - + #line 30 "mulf01.bas" #line 1 "storef.asm" - + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -118,7 +118,7 @@ __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory pop hl ; HL <- IX add hl, de ; HL <- IX + HL pop de - + __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register ex af, af' ld a, (hl) @@ -126,7 +126,7 @@ __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address ld h, (hl) ld l, a ; HL = (HL) ex af, af' - + __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), a inc hl @@ -138,9 +138,9 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL inc hl ld (hl), b ret - + #line 31 "mulf01.bas" - + ZXBASIC_USER_DATA: _a: DEFB 80h diff --git a/tests/functional/mulf16a.asm b/tests/functional/mulf16a.asm index 6316c515b..69e370f91 100644 --- a/tests/functional/mulf16a.asm +++ b/tests/functional/mulf16a.asm @@ -36,49 +36,49 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "mulf16.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "mulf16.asm" #line 1 "_mul32.asm" - - + + ; Ripped from: http://www.andreadrian.de/oldcpu/z80_number_cruncher.html#moztocid784223 ; Used with permission. ; Multiplies 32x32 bit integer (DEHL x D'E'H'L') ; 64bit result is returned in H'L'H L B'C'A C - - + + __MUL32_64START: push hl exx @@ -87,18 +87,18 @@ __MUL32_64START: pop hl ; HL = Load Part (B) ex de, hl ; DE = Low Part (B), HL = HightPart(A) (must be in B'C') push hl - + exx pop bc ; B'C' = HightPart(A) exx ; A = B'C'BC , B = D'E'DE - + ; multiply routine 32 * 32bit = 64bit ; h'l'hlb'c'ac = b'c'bc * d'e'de ; needs register a, changes flags ; ; this routine was with tiny differences in the ; sinclair zx81 rom for the mantissa multiply - + __LMUL: and a ; reset carry flag sbc hl,hl ; result bits 32..47 = 0 @@ -107,8 +107,8 @@ __LMUL: exx ld a,b ; mpr is b'c'ac ld b,33 ; initialize loop counter - jp __LMULSTART - + jp __LMULSTART + __LMULLOOP: jr nc,__LMULNOADD ; JP is 2 cycles faster than JR. Since it's inside a LOOP ; it can save up to 33 * 2 = 66 cycles @@ -117,7 +117,7 @@ __LMULLOOP: exx adc hl,de exx - + __LMULNOADD: exx rr h ; right shift upper @@ -125,7 +125,7 @@ __LMULNOADD: exx rr h rr l - + __LMULSTART: exx rr b ; right shift mpr/ @@ -134,29 +134,29 @@ __LMULSTART: rra ; equivalent to rr a rr c djnz __LMULLOOP - + ret ; result in h'l'hlb'c'ac - + #line 3 "mulf16.asm" - -__MULF16: ; + +__MULF16: ; ld a, d ; load sgn into a ex af, af' ; saves it call __ABS32 ; convert to positive - - exx + + exx pop hl ; Return address pop de ; Low part ex (sp), hl ; CALLEE caller convention; Now HL = Hight part, (SP) = Return address ex de, hl ; D'E' = High part (B), H'L' = Low part (B) (must be in DE) - + ex af, af' xor d ; A register contains resulting sgn ex af, af' call __ABS32 ; convert to positive - + call __MUL32_64START - + ; rounding (was not included in zx81) __ROUND_FIX: ; rounds a 64bit (32.32) fixed point number to 16.16 ; result returned in dehl @@ -166,21 +166,21 @@ __ROUND_FIX: ; rounds a 64bit (32.32) fixed point number to 16.16 ld hl,0 ; ld does not change carry adc hl,bc ; hl = hl + 0 + carry push hl - + exx ld bc,0 - adc hl,bc ; hl = hl + 0 + carry + adc hl,bc ; hl = hl + 0 + carry ex de, hl pop hl ; rounded result in de.hl - + ex af, af' ; recovers result sign or a jp m, __NEG32 ; if negative, negates it - - ret - + + ret + #line 27 "mulf16a.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00h diff --git a/tests/functional/nir.asm b/tests/functional/nir.asm index d0c7114cf..4eee829b0 100644 --- a/tests/functional/nir.asm +++ b/tests/functional/nir.asm @@ -50,7 +50,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _sprite: DEFB 00 diff --git a/tests/functional/octal.asm b/tests/functional/octal.asm index e8635a22a..9bde80d5f 100644 --- a/tests/functional/octal.asm +++ b/tests/functional/octal.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 3Dh diff --git a/tests/functional/ongoto.asm b/tests/functional/ongoto.asm index 6b4de7a23..5f1bc7b6a 100644 --- a/tests/functional/ongoto.asm +++ b/tests/functional/ongoto.asm @@ -140,21 +140,21 @@ __LABEL5: DEFW __LABEL__50 DEFW __LABEL__60 #line 1 "ongoto.asm" - + ; ------------------------------------------------------ ; Implements ON .. GOTO ; ------------------------------------------------------ - + __ON_GOSUB: pop hl ex (sp), hl ; hl = beginning of table call __ON_GOTO_START ret - + __ON_GOTO: pop hl ex (sp), hl ; hl = beginning of table - + __ON_GOTO_START: ; hl = address of jump table ; a = index (0..255) @@ -174,17 +174,17 @@ __ON_GOTO_START: jp (hl) #line 127 "ongoto.bas" #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -192,46 +192,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -244,43 +244,43 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -288,12 +288,12 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -301,51 +301,51 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "in_screen.asm" - + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -354,17 +354,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -372,26 +372,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -405,45 +405,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -454,28 +454,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -483,28 +483,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -513,83 +513,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -598,32 +598,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -633,7 +633,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -641,20 +641,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -664,7 +664,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -675,19 +675,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -697,7 +697,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -708,19 +708,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -730,7 +730,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -743,22 +743,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -767,79 +767,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -848,75 +848,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -926,7 +926,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -938,16 +938,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -961,49 +961,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1014,17 +1014,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1037,27 +1037,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1065,10 +1065,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1085,80 +1085,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1175,8 +1175,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1200,17 +1200,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1221,7 +1221,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1231,21 +1231,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1264,9 +1264,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1291,21 +1291,21 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 128 "ongoto.bas" #line 1 "printstr.asm" - - - - + + + + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1313,25 +1313,25 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1340,41 +1340,41 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1382,25 +1382,25 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1409,39 +1409,39 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -1449,56 +1449,56 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -1507,57 +1507,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -1566,47 +1566,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -1616,51 +1616,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 5 "printstr.asm" - + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1669,11 +1669,11 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 129 "ongoto.bas" - + ZXBASIC_USER_DATA: _a: DEFB 01h diff --git a/tests/functional/opt2_ifbyte.asm b/tests/functional/opt2_ifbyte.asm index d35e3fa6b..e0968e795 100644 --- a/tests/functional/opt2_ifbyte.asm +++ b/tests/functional/opt2_ifbyte.asm @@ -33,7 +33,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/opt2_labelinfunc.asm b/tests/functional/opt2_labelinfunc.asm index 68c63fb83..162965c75 100644 --- a/tests/functional/opt2_labelinfunc.asm +++ b/tests/functional/opt2_labelinfunc.asm @@ -37,7 +37,7 @@ _procedure__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/opt2_labelinfunc3.asm b/tests/functional/opt2_labelinfunc3.asm index 68c63fb83..162965c75 100644 --- a/tests/functional/opt2_labelinfunc3.asm +++ b/tests/functional/opt2_labelinfunc3.asm @@ -37,7 +37,7 @@ _procedure__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/opt2_labelinfunc4.asm b/tests/functional/opt2_labelinfunc4.asm index 2ab11e7b5..6737fa8d7 100644 --- a/tests/functional/opt2_labelinfunc4.asm +++ b/tests/functional/opt2_labelinfunc4.asm @@ -45,7 +45,7 @@ _procedure_subprocedure__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/opt2_labelinfunc5.asm b/tests/functional/opt2_labelinfunc5.asm index 2ab11e7b5..6737fa8d7 100644 --- a/tests/functional/opt2_labelinfunc5.asm +++ b/tests/functional/opt2_labelinfunc5.asm @@ -45,7 +45,7 @@ _procedure_subprocedure__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/opt2_localu8.asm b/tests/functional/opt2_localu8.asm index 683ae8101..4d8aaaacf 100644 --- a/tests/functional/opt2_localu8.asm +++ b/tests/functional/opt2_localu8.asm @@ -47,7 +47,7 @@ _f__leave: ex (sp), hl exx ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/opt2_pstr.asm b/tests/functional/opt2_pstr.asm index 78cd19a7e..56ae8fe80 100644 --- a/tests/functional/opt2_pstr.asm +++ b/tests/functional/opt2_pstr.asm @@ -60,10 +60,10 @@ __LABEL0: DEFB 61h DEFB 32h #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -71,25 +71,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -98,41 +98,41 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -140,25 +140,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -167,39 +167,39 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -207,56 +207,56 @@ __LABEL0: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -265,57 +265,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -324,47 +324,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -374,17 +374,17 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 48 "opt2_pstr.bas" #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -392,25 +392,25 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -419,51 +419,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -471,12 +471,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -484,16 +484,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -505,27 +505,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -537,7 +537,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -545,15 +545,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -578,14 +578,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -593,25 +593,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -620,37 +620,37 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) pop hl ; Recovers destiny in hl as result ret #line 49 "opt2_pstr.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/opt3_17.asm b/tests/functional/opt3_17.asm index 41a4f9b72..a6b1b8a78 100644 --- a/tests/functional/opt3_17.asm +++ b/tests/functional/opt3_17.asm @@ -27,7 +27,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/opt3_asmexpr.asm b/tests/functional/opt3_asmexpr.asm index e163cd20c..575de22d3 100644 --- a/tests/functional/opt3_asmexpr.asm +++ b/tests/functional/opt3_asmexpr.asm @@ -27,7 +27,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/opt3_atolo1.asm b/tests/functional/opt3_atolo1.asm index 8936ab390..8b85f1f9a 100644 --- a/tests/functional/opt3_atolo1.asm +++ b/tests/functional/opt3_atolo1.asm @@ -32,7 +32,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/opt3_atolo4.asm b/tests/functional/opt3_atolo4.asm index f71dc5f6b..ad241398c 100644 --- a/tests/functional/opt3_atolo4.asm +++ b/tests/functional/opt3_atolo4.asm @@ -31,7 +31,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _kkk: DEFB 00, 00 diff --git a/tests/functional/opt3_atoloinc.asm b/tests/functional/opt3_atoloinc.asm index b8c96c169..c4d35207c 100644 --- a/tests/functional/opt3_atoloinc.asm +++ b/tests/functional/opt3_atoloinc.asm @@ -43,7 +43,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _level: DEFB 00 diff --git a/tests/functional/opt3_dark01.asm b/tests/functional/opt3_dark01.asm index 8c55f8601..2aa028339 100644 --- a/tests/functional/opt3_dark01.asm +++ b/tests/functional/opt3_dark01.asm @@ -41,7 +41,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/opt3_einar.asm b/tests/functional/opt3_einar.asm index f79b43cbc..b39f0c2b1 100644 --- a/tests/functional/opt3_einar.asm +++ b/tests/functional/opt3_einar.asm @@ -66,17 +66,17 @@ __LABEL3: DEFB 4Fh DEFB 4Bh #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -84,46 +84,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -136,43 +136,43 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -180,12 +180,12 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -193,51 +193,51 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "in_screen.asm" - + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -246,17 +246,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -264,26 +264,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -297,45 +297,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -346,28 +346,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -375,28 +375,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -405,83 +405,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -490,32 +490,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -525,7 +525,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -533,20 +533,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -556,7 +556,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -567,19 +567,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -589,7 +589,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -600,19 +600,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -622,7 +622,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -635,22 +635,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -659,79 +659,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -740,75 +740,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -818,7 +818,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -830,16 +830,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -853,49 +853,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -906,17 +906,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -929,27 +929,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -957,10 +957,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -977,80 +977,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1067,8 +1067,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1092,17 +1092,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1113,7 +1113,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1123,21 +1123,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1156,9 +1156,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1183,21 +1183,21 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 53 "opt3_einar.bas" #line 1 "printstr.asm" - - - - + + + + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1205,25 +1205,25 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1232,41 +1232,41 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1274,25 +1274,25 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1301,39 +1301,39 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -1341,56 +1341,56 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -1399,57 +1399,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -1458,47 +1458,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -1508,51 +1508,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 5 "printstr.asm" - + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1561,11 +1561,11 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 54 "opt3_einar.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/opt3_einar04.asm b/tests/functional/opt3_einar04.asm index c2cefcb74..4112b140d 100644 --- a/tests/functional/opt3_einar04.asm +++ b/tests/functional/opt3_einar04.asm @@ -38,7 +38,7 @@ _test: #line 6 _test__leave: ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/opt3_einar05.asm b/tests/functional/opt3_einar05.asm index 4c11463a8..c5f5177c9 100644 --- a/tests/functional/opt3_einar05.asm +++ b/tests/functional/opt3_einar05.asm @@ -32,7 +32,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/opt3_einar06.asm b/tests/functional/opt3_einar06.asm index 21de05b0a..629f85e02 100644 --- a/tests/functional/opt3_einar06.asm +++ b/tests/functional/opt3_einar06.asm @@ -42,7 +42,7 @@ _test__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/opt3_haplo01.asm b/tests/functional/opt3_haplo01.asm index 3c7884ab2..2e3491c4b 100644 --- a/tests/functional/opt3_haplo01.asm +++ b/tests/functional/opt3_haplo01.asm @@ -30,7 +30,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/opt3_lcd5.asm b/tests/functional/opt3_lcd5.asm index e1a0de674..26c366052 100644 --- a/tests/functional/opt3_lcd5.asm +++ b/tests/functional/opt3_lcd5.asm @@ -372,66 +372,66 @@ _ScanNear__leave: exx ret #line 1 "and8.asm" - + ; FASTCALL boolean and 8 version. ; result in Accumulator (0 False, not 0 True) ; __FASTCALL__ version (operands: A, H) ; Performs 8bit and 8bit and returns the boolean - + __AND8: or a ret z ld a, h - ret - + ret + #line 363 "opt3_lcd5.bas" #line 1 "ftou32reg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "ftou32reg.asm" - + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) PROC - + LOCAL __IS_FLOAT - + or a - jr nz, __IS_FLOAT + jr nz, __IS_FLOAT ; Here if it is a ZX ROM Integer - + ld h, c ld l, d ld a, e ; Takes sign: FF = -, 0 = + @@ -439,65 +439,65 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS inc a jp z, __NEG32 ; Negates if negative ret - + __IS_FLOAT: ; Jumps here if it is a true floating point number - ld h, e + ld h, e push hl ; Stores it for later (Contains Sign in H) - + push de push bc - + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + ;ld a, c ; Get exponent sub 128 ; Exponent -= 128 jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 - + __FTOU32REG_LOOP: exx ; Shift C'B' E'D' << 1, output bit stays in Carry sla d rl e rl b rl c - + exx ; Shift DEHL << 1, inserting the carry on the right rl l rl h rl e rl d - + djnz __FTOU32REG_LOOP - + __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative jp m, __NEG32 ; Negates DEHL - + ret - + ENDP - - + + __FTOU8: ; Converts float in C ED LH to Unsigned byte in A call __FTOU32REG ld a, l ret - + #line 364 "opt3_lcd5.bas" #line 1 "lei16.asm" - + __LEI16: PROC LOCAL checkParity @@ -516,9 +516,9 @@ checkParity: ENDP #line 365 "opt3_lcd5.bas" #line 1 "lti16.asm" - + #line 1 "lei8.asm" - + __LEI8: ; Signed <= comparison for 8bit int ; A <= H (registers) PROC @@ -527,10 +527,10 @@ __LEI8: ; Signed <= comparison for 8bit int jr nz, __LTI inc a ret - + __LTI8: ; Test 8 bit values A < H sub h - + __LTI: ; Generic signed comparison jp po, checkParity xor 0x80 @@ -541,7 +541,7 @@ checkParity: ret ENDP #line 2 "lti16.asm" - + __LTI16: ; Test 8 bit values HL < DE ; Returns result in A: 0 = False, !0 = True PROC @@ -558,7 +558,7 @@ checkParity: ret ENDP #line 366 "opt3_lcd5.bas" - + ZXBASIC_USER_DATA: _x: DEFB 00, 00, 00, 00, 00 diff --git a/tests/functional/opt3_lcd6.asm b/tests/functional/opt3_lcd6.asm index c6c408cc3..7328d3db6 100644 --- a/tests/functional/opt3_lcd6.asm +++ b/tests/functional/opt3_lcd6.asm @@ -26,7 +26,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/opt3_ldhlhl.asm b/tests/functional/opt3_ldhlhl.asm index 1aca15fb1..26d1fa621 100644 --- a/tests/functional/opt3_ldhlhl.asm +++ b/tests/functional/opt3_ldhlhl.asm @@ -28,7 +28,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/opt3_proc0.asm b/tests/functional/opt3_proc0.asm index 2e27fdb0d..e02cdb921 100644 --- a/tests/functional/opt3_proc0.asm +++ b/tests/functional/opt3_proc0.asm @@ -53,7 +53,7 @@ _p__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/opt3_sp.asm b/tests/functional/opt3_sp.asm index 841a20d46..2a1762121 100644 --- a/tests/functional/opt3_sp.asm +++ b/tests/functional/opt3_sp.asm @@ -78,40 +78,40 @@ _test__leave: exx ret #line 1 "addf.asm" - + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -127,7 +127,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 2 "addf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) ; All of them uses A EDCB registers as 1st paramter. @@ -136,45 +136,45 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; ; Uses CALLEE convention ; ------------------------------------------------------------- - + __ADDF: ; Addition call __FPSTACK_PUSH2 - + ; ------------- ROM ADD rst 28h defb 0fh ; ADD defb 38h; ; END CALC - + jp __FPSTACK_POP - + #line 69 "opt3_sp.bas" #line 1 "ploadf.asm" - + ; Parameter / Local var load ; A => Offset ; IX = Stack Frame ; RESULT: HL => IX + DE - + #line 1 "iloadf.asm" - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- ((HL)) - + __ILOADF: ld a, (hl) inc hl ld h, (hl) ld l, a - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- (HL) - + __LOADF: ; Loads a 40 bits FP number from address pointed by HL - ld a, (hl) + ld a, (hl) inc hl ld e, (hl) inc hl @@ -184,25 +184,25 @@ __LOADF: ; Loads a 40 bits FP number from address pointed by HL inc hl ld b, (hl) ret - + #line 7 "ploadf.asm" - + __PLOADF: push ix pop hl add hl, de jp __LOADF - + #line 70 "opt3_sp.bas" #line 1 "pstoref.asm" - - ; Stores FP number in A ED CB at location HL+IX - ; HL = Offset - ; IX = Stack Frame - ; A ED CB = FP Number - + + ; Stores FP number in A ED CB at location HL+IX + ; HL = Offset + ; IX = Stack Frame + ; A ED CB = FP Number + #line 1 "storef.asm" - + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -210,7 +210,7 @@ __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory pop hl ; HL <- IX add hl, de ; HL <- IX + HL pop de - + __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register ex af, af' ld a, (hl) @@ -218,7 +218,7 @@ __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address ld h, (hl) ld l, a ; HL = (HL) ex af, af' - + __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), a inc hl @@ -230,54 +230,54 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL inc hl ld (hl), b ret - + #line 7 "pstoref.asm" - - ; Stored a float number in A ED CB into the address pointed by IX + HL -__PSTOREF: - push de - ex de, hl ; DE <- HL - push ix - pop hl ; HL <- IX - add hl, de ; HL <- IX + DE - pop de - jp __STOREF - + + ; Stored a float number in A ED CB into the address pointed by IX + HL +__PSTOREF: + push de + ex de, hl ; DE <- HL + push ix + pop hl ; HL <- IX + add hl, de ; HL <- IX + DE + pop de + jp __STOREF + #line 71 "opt3_sp.bas" #line 1 "u32tofreg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "u32tofreg.asm" __I8TOFREG: ld l, a @@ -286,35 +286,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -322,20 +322,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -343,32 +343,32 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 72 "opt3_sp.bas" - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/optconst.asm b/tests/functional/optconst.asm index f91911d35..72a7d5426 100644 --- a/tests/functional/optconst.asm +++ b/tests/functional/optconst.asm @@ -56,17 +56,17 @@ __LABEL__label2: ld c, l jp __END_PROGRAM #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -74,46 +74,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -126,43 +126,43 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -170,12 +170,12 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -183,51 +183,51 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "in_screen.asm" - + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -236,17 +236,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -254,26 +254,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -287,45 +287,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -336,28 +336,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -365,28 +365,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -395,83 +395,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -480,32 +480,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -515,7 +515,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -523,20 +523,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -546,7 +546,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -557,19 +557,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -579,7 +579,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -590,19 +590,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -612,7 +612,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -625,22 +625,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -649,79 +649,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -730,75 +730,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -808,7 +808,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -820,16 +820,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -843,49 +843,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -896,17 +896,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -919,27 +919,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -947,10 +947,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -967,80 +967,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1057,8 +1057,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1082,17 +1082,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1103,7 +1103,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1113,21 +1113,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1146,9 +1146,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1173,33 +1173,33 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 46 "optconst.bas" #line 1 "printu32.asm" - + #line 1 "printi32.asm" - + #line 1 "printnum.asm" - - - - + + + + __PRINTU_START: PROC - + LOCAL __PRINTU_CONT - + ld a, b or a jp nz, __PRINTU_CONT - + ld a, '0' jp __PRINT_DIGIT - - + + __PRINTU_CONT: pop af push bc @@ -1207,55 +1207,55 @@ __PRINTU_CONT: pop bc djnz __PRINTU_CONT ret - + ENDP - - + + __PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers ld a, '-' jp __PRINT_DIGIT - + __PRINT_DIGIT EQU __PRINTCHAR ; PRINTS the char in A register, and puts its attrs - - + + #line 2 "printi32.asm" #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 3 "printi32.asm" #line 1 "div32.asm" - - - + + + ; --------------------------------------------------------- __DIVU32: ; 32 bit unsigned division ; DEHL = Dividend, Stack Top = Divisor @@ -1267,7 +1267,7 @@ __DIVU32: ; 32 bit unsigned division pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + __DIVU32START: ; Performs D'E'H'L' / HLDE ; Now switch to DIVIDEND = B'C'BC / DIVISOR = D'E'DE (A / B) push de ; push Lowpart(Q) @@ -1283,9 +1283,9 @@ __DIVU32START: ; Performs D'E'H'L' / HLDE exx pop bc ; Pop HightPart(B) => B = B'C'BC exx - + ld a, 32 ; Loop count - + __DIV32LOOP: sll c ; B'C'BC << 1 ; Output most left bit to carry rl b @@ -1293,29 +1293,29 @@ __DIV32LOOP: rl c rl b exx - + adc hl, hl exx adc hl, hl exx - + sbc hl,de exx sbc hl,de exx jp nc, __DIV32NOADD ; use JP inside a loop for being faster - + add hl, de exx adc hl, de exx dec bc - + __DIV32NOADD: dec a jp nz, __DIV32LOOP ; use JP inside a loop for being faster ; At this point, quotient is stored in B'C'BC and the reminder in H'L'HL - + push hl exx pop de @@ -1325,34 +1325,34 @@ __DIV32NOADD: pop de ; DE = B'C' ld h, b ld l, c ; DEHL = quotient D'E'H'L' = Modulus - + ret ; DEHL = quotient, D'E'H'L' = Modulus - - - + + + __MODU32: ; 32 bit modulus for 32bit unsigned division ; DEHL = Dividend, Stack Top = Divisor (DE, HL) - + exx pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + call __DIVU32START ; At return, modulus is at D'E'H'L' - + __MODU32START: - + exx push de push hl - - exx + + exx pop hl pop de - + ret - - + + __DIVI32: ; 32 bit signed division ; DEHL = Dividend, Stack Top = Divisor ; A = Dividend, B = Divisor => A / B @@ -1360,76 +1360,76 @@ __DIVI32: ; 32 bit signed division pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + __DIVI32START: exx ld a, d ; Save sign ex af, af' bit 7, d ; Negative? call nz, __NEG32 ; Negates DEHL - + exx ; Now works with H'L'D'E' ex af, af' xor h ex af, af' ; Stores sign of the result for later - + bit 7, h ; Negative? ex de, hl ; HLDE = DEHL call nz, __NEG32 - ex de, hl - + ex de, hl + call __DIVU32START ex af, af' ; Recovers sign and 128 ; positive? ret z - + jp __NEG32 ; Negates DEHL and returns from there - - + + __MODI32: ; 32bits signed division modulus exx pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + call __DIVI32START - jp __MODU32START - + jp __MODU32START + #line 4 "printi32.asm" - - - + + + __PRINTI32: ld a, d or a jp p, __PRINTU32 - + call __PRINT_MINUS call __NEG32 - + __PRINTU32: PROC LOCAL __PRINTU_LOOP - + ld b, 0 ; Counter - + __PRINTU_LOOP: ld a, h or l or d or e jp z, __PRINTU_START - + push bc - + ld bc, 0 push bc ld bc, 10 push bc ; Push 00 0A (10 Dec) into the stack = divisor - + call __DIVU32 ; Divides by 32. D'E'H'L' contains modulo (L' since < 10) pop bc - + exx ld a, l or '0' ; Stores ASCII digit (must be print in reversed order) @@ -1437,13 +1437,13 @@ __PRINTU_LOOP: exx inc b jp __PRINTU_LOOP ; Uses JP in loops - + ENDP - + #line 2 "printu32.asm" - + #line 47 "optconst.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00 diff --git a/tests/functional/or16.asm b/tests/functional/or16.asm index 58c74ca07..2926de5f0 100644 --- a/tests/functional/or16.asm +++ b/tests/functional/or16.asm @@ -47,7 +47,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/or32.asm b/tests/functional/or32.asm index 23935253e..86a050bfd 100644 --- a/tests/functional/or32.asm +++ b/tests/functional/or32.asm @@ -67,31 +67,31 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "or32.asm" - + __OR32: ; Performs logical operation A AND B ; between DEHL and TOP of the stack. ; Returns A = 0 (False) or A = FF (True) - + ld a, h or l or d or e - + pop hl ; Return address - - pop de + + pop de or d or e - - pop de + + pop de or d or e ; A = 0 only if DEHL and TOP of the stack = 0 - + jp (hl) ; Faster "Ret" - - + + #line 58 "or32.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00 diff --git a/tests/functional/or8.asm b/tests/functional/or8.asm index c377cb25c..438e76117 100644 --- a/tests/functional/or8.asm +++ b/tests/functional/or8.asm @@ -40,7 +40,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/out0.asm b/tests/functional/out0.asm index 2a05f6fd5..b06c66cc1 100644 --- a/tests/functional/out0.asm +++ b/tests/functional/out0.asm @@ -37,52 +37,52 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "ftou32reg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "ftou32reg.asm" - + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) PROC - + LOCAL __IS_FLOAT - + or a - jr nz, __IS_FLOAT + jr nz, __IS_FLOAT ; Here if it is a ZX ROM Integer - + ld h, c ld l, d ld a, e ; Takes sign: FF = -, 0 = + @@ -90,64 +90,64 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS inc a jp z, __NEG32 ; Negates if negative ret - + __IS_FLOAT: ; Jumps here if it is a true floating point number - ld h, e + ld h, e push hl ; Stores it for later (Contains Sign in H) - + push de push bc - + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + ;ld a, c ; Get exponent sub 128 ; Exponent -= 128 jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 - + __FTOU32REG_LOOP: exx ; Shift C'B' E'D' << 1, output bit stays in Carry sla d rl e rl b rl c - + exx ; Shift DEHL << 1, inserting the carry on the right rl l rl h rl e rl d - + djnz __FTOU32REG_LOOP - + __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative jp m, __NEG32 ; Negates DEHL - + ret - + ENDP - - + + __FTOU8: ; Converts float in C ED LH to Unsigned byte in A call __FTOU32REG ld a, l ret - + #line 28 "out0.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00, 00 diff --git a/tests/functional/param0.asm b/tests/functional/param0.asm index 748cef369..4fad8e6c7 100644 --- a/tests/functional/param0.asm +++ b/tests/functional/param0.asm @@ -69,10 +69,10 @@ __LABEL1: DEFW 0001h DEFB 41h #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -80,25 +80,25 @@ __LABEL1: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -107,41 +107,41 @@ __LABEL1: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -149,25 +149,25 @@ __LABEL1: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -176,39 +176,39 @@ __LABEL1: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -216,56 +216,56 @@ __LABEL1: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -274,57 +274,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -333,47 +333,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -383,17 +383,17 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 56 "param0.bas" #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -401,25 +401,25 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -428,51 +428,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -480,12 +480,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -493,16 +493,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -514,27 +514,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -546,7 +546,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -554,15 +554,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -587,14 +587,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -602,25 +602,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -629,30 +629,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -660,17 +660,17 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 57 "param0.bas" #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -678,46 +678,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -730,67 +730,67 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - - - + + + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -799,17 +799,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -817,26 +817,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -850,45 +850,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -899,28 +899,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -928,28 +928,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -958,83 +958,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -1043,32 +1043,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -1078,7 +1078,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -1086,20 +1086,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -1109,7 +1109,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -1120,19 +1120,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -1142,7 +1142,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -1153,19 +1153,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -1175,7 +1175,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -1188,22 +1188,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -1212,79 +1212,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -1293,75 +1293,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -1371,7 +1371,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -1383,16 +1383,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1406,49 +1406,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1459,17 +1459,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1482,27 +1482,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1510,10 +1510,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1530,80 +1530,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1620,8 +1620,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1645,17 +1645,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1666,7 +1666,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1676,21 +1676,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1709,9 +1709,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1736,58 +1736,58 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 58 "param0.bas" #line 1 "printstr.asm" - - - - - - + + + + + + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1796,107 +1796,107 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 59 "param0.bas" #line 1 "strcat.asm" - - + + #line 1 "strlen.asm" - + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL - + __STRLEN: ; Direct FASTCALL entry ld a, h or l ret z - + ld a, (hl) inc hl ld h, (hl) ; LEN(str) in HL ld l, a ret - - + + #line 3 "strcat.asm" - + __ADDSTR: ; Implements c$ = a$ + b$ ; hl = &a$, de = &b$ (pointers) - - + + __STRCAT2: ; This routine creates a new string in dynamic space ; making room for it. Then copies a$ + b$ into it. ; HL = a$, DE = b$ - + PROC - + LOCAL __STR_CONT LOCAL __STRCATEND - + push hl call __STRLEN ld c, l ld b, h ; BC = LEN(a$) ex (sp), hl ; (SP) = LEN (a$), HL = a$ push hl ; Saves pointer to a$ - + inc bc inc bc ; +2 bytes to store length - + ex de, hl push hl call __STRLEN ; HL = len(b$) - + add hl, bc ; Total str length => 2 + len(a$) + len(b$) - + ld c, l ld b, h ; BC = Total str length + 2 - call __MEM_ALLOC - pop de ; HL = c$, DE = b$ - + call __MEM_ALLOC + pop de ; HL = c$, DE = b$ + ex de, hl ; HL = b$, DE = c$ - ex (sp), hl ; HL = a$, (SP) = b$ - + ex (sp), hl ; HL = a$, (SP) = b$ + exx - pop de ; D'E' = b$ + pop de ; D'E' = b$ exx - + pop bc ; LEN(a$) - + ld a, d or e ret z ; If no memory: RETURN - + __STR_CONT: push de ; Address of c$ - + ld a, h or l jr nz, __STR_CONT1 ; If len(a$) != 0 do copy - + ; a$ is NULL => uses HL = DE for transfer ld h, d ld l, e ld (hl), a ; This will copy 00 00 at (DE) location - inc de ; + inc de ; dec bc ; Ensure BC will be set to 1 in the next step - + __STR_CONT1: ; Copies a$ (HL) into c$ (DE) - inc bc + inc bc inc bc ; BC = BC + 2 ldir ; MEMCOPY: c$ = a$ pop hl ; HL = c$ - + exx push de ; Recovers b$; A ex hl,hl' would be very handy exx - - pop de ; DE = b$ - + + pop de ; DE = b$ + __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ; NOTE: Both DE, BC and AF are modified and lost ; Returns HL (pointer to a$) @@ -1904,50 +1904,50 @@ __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ld a, d or e ret z ; Returns if de is NULL (nothing to copy) - + push hl ; Saves HL to return it later - + ld c, (hl) inc hl ld b, (hl) inc hl add hl, bc ; HL = end of (a$) string ; bc = len(a$) push bc ; Saves LEN(a$) for later - + ex de, hl ; DE = end of string (Begin of copy addr) ld c, (hl) inc hl ld b, (hl) ; BC = len(b$) - + ld a, b or c jr z, __STRCATEND; Return if len(b$) == 0 - + push bc ; Save LEN(b$) inc hl ; Skip 2nd byte of len(b$) ldir ; Concatenate b$ - + pop bc ; Recovers length (b$) pop hl ; Recovers length (a$) add hl, bc ; HL = LEN(a$) + LEN(b$) = LEN(a$+b$) ex de, hl ; DE = LEN(a$+b$) pop hl - + ld (hl), e ; Updates new LEN and return inc hl ld (hl), d dec hl ret - + __STRCATEND: pop hl ; Removes Len(a$) pop hl ; Restores original HL, so HL = a$ ret - + ENDP - + #line 60 "param0.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/param1.asm b/tests/functional/param1.asm index 769bb9233..7a9b86b67 100644 --- a/tests/functional/param1.asm +++ b/tests/functional/param1.asm @@ -61,22 +61,22 @@ __LABEL0: DEFW 0001h DEFB 61h #line 1 "print_eol_attr.asm" - + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes - + #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -84,46 +84,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -136,43 +136,43 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -180,12 +180,12 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -193,51 +193,51 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "in_screen.asm" - + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -246,17 +246,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -264,26 +264,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -297,45 +297,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -346,28 +346,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -375,28 +375,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -405,83 +405,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -490,32 +490,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -525,7 +525,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -533,20 +533,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -556,7 +556,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -567,19 +567,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -589,7 +589,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -600,19 +600,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -622,7 +622,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -635,22 +635,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -659,79 +659,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -740,75 +740,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -818,7 +818,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -830,16 +830,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -853,49 +853,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -906,17 +906,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -929,27 +929,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -957,10 +957,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -977,80 +977,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1067,8 +1067,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1092,17 +1092,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1113,7 +1113,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1123,21 +1123,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1156,9 +1156,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1183,27 +1183,27 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 5 "print_eol_attr.asm" - - + + PRINT_EOL_ATTR: call PRINT_EOL jp COPY_ATTR #line 48 "param1.bas" #line 1 "printstr.asm" - - - - + + + + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1211,25 +1211,25 @@ PRINT_EOL_ATTR: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1238,41 +1238,41 @@ PRINT_EOL_ATTR: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1280,25 +1280,25 @@ PRINT_EOL_ATTR: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1307,39 +1307,39 @@ PRINT_EOL_ATTR: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -1347,56 +1347,56 @@ PRINT_EOL_ATTR: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -1405,57 +1405,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -1464,47 +1464,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -1514,51 +1514,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 5 "printstr.asm" - + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1567,12 +1567,12 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 49 "param1.bas" #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -1583,15 +1583,15 @@ __PRINT_STR: ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1599,25 +1599,25 @@ __PRINT_STR: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1626,43 +1626,43 @@ __PRINT_STR: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1670,25 +1670,25 @@ __PRINT_STR: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1697,40 +1697,40 @@ __PRINT_STR: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - - + + + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -1742,27 +1742,27 @@ __PRINT_STR: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -1774,7 +1774,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -1782,15 +1782,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -1815,14 +1815,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -1830,23 +1830,23 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 71 "realloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -1865,29 +1865,29 @@ __MEM_SUBTRACT: ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -1896,111 +1896,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -2016,7 +2016,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -2024,44 +2024,44 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 50 "param1.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/param2.asm b/tests/functional/param2.asm index dc5073be2..20fac6bc1 100644 --- a/tests/functional/param2.asm +++ b/tests/functional/param2.asm @@ -69,10 +69,10 @@ __LABEL1: DEFW 0001h DEFB 41h #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -80,25 +80,25 @@ __LABEL1: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -107,41 +107,41 @@ __LABEL1: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -149,25 +149,25 @@ __LABEL1: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -176,39 +176,39 @@ __LABEL1: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -216,56 +216,56 @@ __LABEL1: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -274,57 +274,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -333,47 +333,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -383,17 +383,17 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 56 "param2.bas" #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -401,25 +401,25 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -428,51 +428,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -480,12 +480,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -493,16 +493,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -514,27 +514,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -546,7 +546,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -554,15 +554,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -587,14 +587,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -602,25 +602,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -629,30 +629,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -660,17 +660,17 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 57 "param2.bas" #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -678,46 +678,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -730,67 +730,67 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - - - + + + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -799,17 +799,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -817,26 +817,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -850,45 +850,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -899,28 +899,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -928,28 +928,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -958,83 +958,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -1043,32 +1043,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -1078,7 +1078,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -1086,20 +1086,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -1109,7 +1109,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -1120,19 +1120,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -1142,7 +1142,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -1153,19 +1153,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -1175,7 +1175,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -1188,22 +1188,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -1212,79 +1212,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -1293,75 +1293,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -1371,7 +1371,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -1383,16 +1383,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1406,49 +1406,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1459,17 +1459,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1482,27 +1482,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1510,10 +1510,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1530,80 +1530,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1620,8 +1620,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1645,17 +1645,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1666,7 +1666,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1676,21 +1676,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1709,9 +1709,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1736,58 +1736,58 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 58 "param2.bas" #line 1 "printstr.asm" - - - - - - + + + + + + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1796,107 +1796,107 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 59 "param2.bas" #line 1 "strcat.asm" - - + + #line 1 "strlen.asm" - + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL - + __STRLEN: ; Direct FASTCALL entry ld a, h or l ret z - + ld a, (hl) inc hl ld h, (hl) ; LEN(str) in HL ld l, a ret - - + + #line 3 "strcat.asm" - + __ADDSTR: ; Implements c$ = a$ + b$ ; hl = &a$, de = &b$ (pointers) - - + + __STRCAT2: ; This routine creates a new string in dynamic space ; making room for it. Then copies a$ + b$ into it. ; HL = a$, DE = b$ - + PROC - + LOCAL __STR_CONT LOCAL __STRCATEND - + push hl call __STRLEN ld c, l ld b, h ; BC = LEN(a$) ex (sp), hl ; (SP) = LEN (a$), HL = a$ push hl ; Saves pointer to a$ - + inc bc inc bc ; +2 bytes to store length - + ex de, hl push hl call __STRLEN ; HL = len(b$) - + add hl, bc ; Total str length => 2 + len(a$) + len(b$) - + ld c, l ld b, h ; BC = Total str length + 2 - call __MEM_ALLOC - pop de ; HL = c$, DE = b$ - + call __MEM_ALLOC + pop de ; HL = c$, DE = b$ + ex de, hl ; HL = b$, DE = c$ - ex (sp), hl ; HL = a$, (SP) = b$ - + ex (sp), hl ; HL = a$, (SP) = b$ + exx - pop de ; D'E' = b$ + pop de ; D'E' = b$ exx - + pop bc ; LEN(a$) - + ld a, d or e ret z ; If no memory: RETURN - + __STR_CONT: push de ; Address of c$ - + ld a, h or l jr nz, __STR_CONT1 ; If len(a$) != 0 do copy - + ; a$ is NULL => uses HL = DE for transfer ld h, d ld l, e ld (hl), a ; This will copy 00 00 at (DE) location - inc de ; + inc de ; dec bc ; Ensure BC will be set to 1 in the next step - + __STR_CONT1: ; Copies a$ (HL) into c$ (DE) - inc bc + inc bc inc bc ; BC = BC + 2 ldir ; MEMCOPY: c$ = a$ pop hl ; HL = c$ - + exx push de ; Recovers b$; A ex hl,hl' would be very handy exx - - pop de ; DE = b$ - + + pop de ; DE = b$ + __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ; NOTE: Both DE, BC and AF are modified and lost ; Returns HL (pointer to a$) @@ -1904,50 +1904,50 @@ __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ld a, d or e ret z ; Returns if de is NULL (nothing to copy) - + push hl ; Saves HL to return it later - + ld c, (hl) inc hl ld b, (hl) inc hl add hl, bc ; HL = end of (a$) string ; bc = len(a$) push bc ; Saves LEN(a$) for later - + ex de, hl ; DE = end of string (Begin of copy addr) ld c, (hl) inc hl ld b, (hl) ; BC = len(b$) - + ld a, b or c jr z, __STRCATEND; Return if len(b$) == 0 - + push bc ; Save LEN(b$) inc hl ; Skip 2nd byte of len(b$) ldir ; Concatenate b$ - + pop bc ; Recovers length (b$) pop hl ; Recovers length (a$) add hl, bc ; HL = LEN(a$) + LEN(b$) = LEN(a$+b$) ex de, hl ; DE = LEN(a$+b$) pop hl - + ld (hl), e ; Updates new LEN and return inc hl ld (hl), d dec hl ret - + __STRCATEND: pop hl ; Removes Len(a$) pop hl ; Restores original HL, so HL = a$ ret - + ENDP - + #line 60 "param2.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/parambyref1.asm b/tests/functional/parambyref1.asm index 5f74839fb..6fc2b98b9 100644 --- a/tests/functional/parambyref1.asm +++ b/tests/functional/parambyref1.asm @@ -69,17 +69,17 @@ _test__leave: exx ret #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -87,46 +87,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -139,43 +139,43 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -183,12 +183,12 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -196,51 +196,51 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "in_screen.asm" - + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -249,17 +249,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -267,26 +267,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -300,45 +300,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -349,28 +349,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -378,28 +378,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -408,83 +408,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -493,32 +493,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -528,7 +528,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -536,20 +536,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -559,7 +559,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -570,19 +570,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -592,7 +592,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -603,19 +603,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -625,7 +625,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -638,22 +638,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -662,79 +662,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -743,75 +743,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -821,7 +821,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -833,16 +833,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -856,49 +856,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -909,17 +909,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -932,27 +932,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -960,10 +960,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -980,80 +980,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1070,8 +1070,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1095,17 +1095,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1116,7 +1116,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1126,21 +1126,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1159,9 +1159,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1186,33 +1186,33 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 59 "parambyref1.bas" #line 1 "printu16.asm" - + #line 1 "printi16.asm" - + #line 1 "printnum.asm" - - - - + + + + __PRINTU_START: PROC - + LOCAL __PRINTU_CONT - + ld a, b or a jp nz, __PRINTU_CONT - + ld a, '0' jp __PRINT_DIGIT - - + + __PRINTU_CONT: pop af push bc @@ -1220,30 +1220,30 @@ __PRINTU_CONT: pop bc djnz __PRINTU_CONT ret - + ENDP - - + + __PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers ld a, '-' jp __PRINT_DIGIT - + __PRINT_DIGIT EQU __PRINTCHAR ; PRINTS the char in A register, and puts its attrs - - + + #line 2 "printi16.asm" #line 1 "div16.asm" - - ; 16 bit division and modulo functions + + ; 16 bit division and modulo functions ; for both signed and unsigned values - + #line 1 "neg16.asm" - + ; Negates HL value (16 bit) __ABS16: bit 7, h ret z - + __NEGHL: ld a, l ; HL = -HL cpl @@ -1253,23 +1253,23 @@ __NEGHL: ld h, a inc hl ret - + #line 5 "div16.asm" - + __DIVU16: ; 16 bit unsigned division ; HL = Dividend, Stack Top = Divisor - + ; -- OBSOLETE ; Now uses FASTCALL convention ; ex de, hl ; pop hl ; Return address ; ex (sp), hl ; CALLEE Convention - + __DIVU16_FAST: ld a, h ld c, l ld hl, 0 ld b, 16 - + __DIV16LOOP: sll c rla @@ -1278,46 +1278,46 @@ __DIV16LOOP: jr nc, __DIV16NOADD add hl,de dec c - + __DIV16NOADD: djnz __DIV16LOOP - + ex de, hl ld h, a ld l, c - + ret ; HL = quotient, DE = Mudulus - - - + + + __MODU16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVU16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - - + + __DIVI16: ; 16 bit signed division ; --- The following is OBSOLETE --- ; ex de, hl ; pop hl ; ex (sp), hl ; CALLEE Convention - + __DIVI16_FAST: ld a, d xor h ex af, af' ; BIT 7 of a contains result - + bit 7, d ; DE is negative? - jr z, __DIVI16A - + jr z, __DIVI16A + ld a, e ; DE = -DE cpl ld e, a @@ -1325,75 +1325,75 @@ __DIVI16_FAST: cpl ld d, a inc de - + __DIVI16A: bit 7, h ; HL is negative? call nz, __NEGHL - + __DIVI16B: call __DIVU16_FAST ex af, af' - - or a + + or a ret p ; return if positive jp __NEGHL - - + + __MODI16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVI16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - + #line 3 "printi16.asm" - - - + + + __PRINTI16: ; Prints a 16bits signed in HL ; Converts 16 to 32 bits PROC - + LOCAL __PRINTU_LOOP ld a, h or a - + jp p, __PRINTU16 - + call __PRINT_MINUS call __NEGHL - + __PRINTU16: - + ld b, 0 __PRINTU_LOOP: ld a, h or l jp z, __PRINTU_START - + push bc ld de, 10 call __DIVU16_FAST ; Divides by DE. DE = MODULUS at exit. Since < 256, E = Modulus pop bc - + ld a, e or '0' ; Stores ASCII digit (must be print in reversed order) push af inc b jp __PRINTU_LOOP ; Uses JP in loops - + ENDP - + #line 2 "printu16.asm" - + #line 60 "parambyref1.bas" - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/paramint3.asm b/tests/functional/paramint3.asm index 1832a2a9b..bbe6343ad 100644 --- a/tests/functional/paramint3.asm +++ b/tests/functional/paramint3.asm @@ -41,7 +41,7 @@ _p__leave: ex (sp), hl exx ret - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/paramstr3.asm b/tests/functional/paramstr3.asm index 19b3f0886..d72d2ec1c 100644 --- a/tests/functional/paramstr3.asm +++ b/tests/functional/paramstr3.asm @@ -53,10 +53,10 @@ _p__leave: exx ret #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -64,25 +64,25 @@ _p__leave: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -91,41 +91,41 @@ _p__leave: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -133,25 +133,25 @@ _p__leave: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -160,39 +160,39 @@ _p__leave: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -200,56 +200,56 @@ _p__leave: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -258,57 +258,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -317,47 +317,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -367,17 +367,17 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 41 "paramstr3.bas" #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -385,25 +385,25 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -412,51 +412,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -464,12 +464,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -477,16 +477,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -498,27 +498,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -530,7 +530,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -538,15 +538,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -571,14 +571,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -586,25 +586,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -613,37 +613,37 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) pop hl ; Recovers destiny in hl as result ret #line 42 "paramstr3.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/paramstr4.asm b/tests/functional/paramstr4.asm index c30ff69fb..d16de88a5 100644 --- a/tests/functional/paramstr4.asm +++ b/tests/functional/paramstr4.asm @@ -77,10 +77,10 @@ _r__leave: exx ret #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -88,25 +88,25 @@ _r__leave: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -115,41 +115,41 @@ _r__leave: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -157,25 +157,25 @@ _r__leave: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -184,39 +184,39 @@ _r__leave: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -224,56 +224,56 @@ _r__leave: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -282,57 +282,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -341,47 +341,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -391,17 +391,17 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 65 "paramstr4.bas" #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -409,25 +409,25 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -436,51 +436,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -488,12 +488,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -501,16 +501,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -522,27 +522,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -554,7 +554,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -562,15 +562,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -595,14 +595,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -610,25 +610,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -637,37 +637,37 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) pop hl ; Recovers destiny in hl as result ret #line 66 "paramstr4.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/paramstr5.asm b/tests/functional/paramstr5.asm index d52f1bd2b..a25a1fe3a 100644 --- a/tests/functional/paramstr5.asm +++ b/tests/functional/paramstr5.asm @@ -77,10 +77,10 @@ _p_r__leave: exx ret #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -88,25 +88,25 @@ _p_r__leave: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -115,41 +115,41 @@ _p_r__leave: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -157,25 +157,25 @@ _p_r__leave: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -184,39 +184,39 @@ _p_r__leave: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -224,56 +224,56 @@ _p_r__leave: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -282,57 +282,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -341,47 +341,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -391,17 +391,17 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 65 "paramstr5.bas" #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -409,25 +409,25 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -436,51 +436,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -488,12 +488,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -501,16 +501,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -522,27 +522,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -554,7 +554,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -562,15 +562,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -595,14 +595,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -610,25 +610,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -637,37 +637,37 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) pop hl ; Recovers destiny in hl as result ret #line 66 "paramstr5.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/plot.asm b/tests/functional/plot.asm index 61e6b2738..a8700f670 100644 --- a/tests/functional/plot.asm +++ b/tests/functional/plot.asm @@ -59,52 +59,52 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "ftou32reg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "ftou32reg.asm" - + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) PROC - + LOCAL __IS_FLOAT - + or a - jr nz, __IS_FLOAT + jr nz, __IS_FLOAT ; Here if it is a ZX ROM Integer - + ld h, c ld l, d ld a, e ; Takes sign: FF = -, 0 = + @@ -112,86 +112,86 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS inc a jp z, __NEG32 ; Negates if negative ret - + __IS_FLOAT: ; Jumps here if it is a true floating point number - ld h, e + ld h, e push hl ; Stores it for later (Contains Sign in H) - + push de push bc - + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + ;ld a, c ; Get exponent sub 128 ; Exponent -= 128 jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 - + __FTOU32REG_LOOP: exx ; Shift C'B' E'D' << 1, output bit stays in Carry sla d rl e rl b rl c - + exx ; Shift DEHL << 1, inserting the carry on the right rl l rl h rl e rl d - + djnz __FTOU32REG_LOOP - + __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative jp m, __NEG32 ; Negates DEHL - + ret - + ENDP - - + + __FTOU8: ; Converts float in C ED LH to Unsigned byte in A call __FTOU32REG ld a, l ret - + #line 50 "plot.bas" #line 1 "plot.asm" - + ; MIXED __FASTCAL__ / __CALLE__ PLOT Function ; Plots a point into the screen calling the ZX ROM PLOT routine - + ; Y in A (accumulator) ; X in top of the stack - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -199,12 +199,12 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -212,7 +212,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -220,13 +220,13 @@ __STOP: ret #line 8 "plot.asm" #line 1 "in_screen.asm" - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -234,75 +234,75 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 2 "in_screen.asm" - - + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 9 "plot.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -315,48 +315,48 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 10 "plot.asm" - + PLOT: PROC - + LOCAL PLOT_SUB LOCAL PIXEL_ADDR LOCAL COORDS LOCAL __PLOT_ERR LOCAL P_FLAG LOCAL __PLOT_OVER1 - + P_FLAG EQU 23697 - + pop hl ex (sp), hl ; Callee - + ld b, a - ld c, h - + ld c, h + ld a, 191 cp b jr c, __PLOT_ERR ; jr is faster here (#1) - + __PLOT: ; __FASTCALL__ entry (b, c) = pixel coords (y, x) ld (COORDS), bc ; Saves current point ld a, 191 ; Max y coord @@ -364,7 +364,7 @@ __PLOT: ; __FASTCALL__ entry (b, c) = pixel coords (y, x) res 6, h ; Starts from 0 ld bc, (SCREEN_ADDR) add hl, bc ; Now current offset - + ld b, a inc b ld a, 0FEh @@ -372,7 +372,7 @@ __PLOT: ; __FASTCALL__ entry (b, c) = pixel coords (y, x) __PLOT_LOOP: rrca djnz __PLOT_LOOP - + ld b, a ld a, (P_FLAG) ld c, a @@ -380,18 +380,18 @@ __PLOT_LOOP: bit 0, c ; is it OVER 1 jr nz, __PLOT_OVER1 and b - + __PLOT_OVER1: bit 2, c ; is it inverse 1 jr nz, __PLOT_END - + xor b cpl - + LOCAL __PLOT_END __PLOT_END: ld (hl), a - + ;; gets ATTR position with offset given in SCREEN_ADDR ld a, h rrca @@ -402,20 +402,20 @@ __PLOT_END: ld h, a ld de, (SCREEN_ADDR) add hl, de ;; Final screen addr - + LOCAL PO_ATTR_2 PO_ATTR_2 EQU 0BE4h ; Another entry to PO_ATTR jp PO_ATTR_2 ; This will update attr accordingly. Beware, uses IY - + __PLOT_ERR: jp __OUT_OF_SCREEN_ERR ; Spent 3 bytes, but saves 3 T-States at (#1) - + PLOT_SUB EQU 22ECh - PIXEL_ADDR EQU 22ACh + PIXEL_ADDR EQU 22ACh COORDS EQU 5C7Dh ENDP #line 51 "plot.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00, 00 diff --git a/tests/functional/poke0.asm b/tests/functional/poke0.asm index c84eea43c..08c1c3f4f 100644 --- a/tests/functional/poke0.asm +++ b/tests/functional/poke0.asm @@ -46,7 +46,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _i: DEFB 00h diff --git a/tests/functional/poke1.asm b/tests/functional/poke1.asm index 7e7e70132..bd47e6118 100644 --- a/tests/functional/poke1.asm +++ b/tests/functional/poke1.asm @@ -76,7 +76,7 @@ _test__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: __LABEL5: DEFB 00h diff --git a/tests/functional/poke2.asm b/tests/functional/poke2.asm index c84eea43c..08c1c3f4f 100644 --- a/tests/functional/poke2.asm +++ b/tests/functional/poke2.asm @@ -46,7 +46,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _i: DEFB 00h diff --git a/tests/functional/pokeref.asm b/tests/functional/pokeref.asm index 13a59af05..281954dd1 100644 --- a/tests/functional/pokeref.asm +++ b/tests/functional/pokeref.asm @@ -28,7 +28,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/pokeref1.asm b/tests/functional/pokeref1.asm index 55bd1ad0d..6bc56657f 100644 --- a/tests/functional/pokeref1.asm +++ b/tests/functional/pokeref1.asm @@ -36,7 +36,7 @@ _test__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/pokeref2.asm b/tests/functional/pokeref2.asm index 07b139ca3..ac2feab70 100644 --- a/tests/functional/pokeref2.asm +++ b/tests/functional/pokeref2.asm @@ -44,7 +44,7 @@ _printat42__leave: ex (sp), hl exx ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/pooky0.asm b/tests/functional/pooky0.asm index 68874614d..c68a6816e 100644 --- a/tests/functional/pooky0.asm +++ b/tests/functional/pooky0.asm @@ -151,40 +151,40 @@ __EXIT_FUNCTION: exx ret #line 1 "addf.asm" - + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -200,7 +200,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 2 "addf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) ; All of them uses A EDCB registers as 1st paramter. @@ -209,22 +209,22 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; ; Uses CALLEE convention ; ------------------------------------------------------------- - + __ADDF: ; Addition call __FPSTACK_PUSH2 - + ; ------------- ROM ADD rst 28h defb 0fh ; ADD defb 38h; ; END CALC - + jp __FPSTACK_POP - + #line 142 "pooky0.bas" #line 1 "mulf.asm" - - - + + + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) ; All of them uses A EDCB registers as 1st paramter. @@ -233,45 +233,45 @@ __ADDF: ; Addition ; ; Uses CALLEE convention ; ------------------------------------------------------------- - + __MULF: ; Multiplication call __FPSTACK_PUSH2 - + ; ------------- ROM MUL rst 28h - defb 04h ; + defb 04h ; defb 38h; ; END CALC - + jp __FPSTACK_POP - + #line 143 "pooky0.bas" #line 1 "ploadf.asm" - + ; Parameter / Local var load ; A => Offset ; IX = Stack Frame ; RESULT: HL => IX + DE - + #line 1 "iloadf.asm" - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- ((HL)) - + __ILOADF: ld a, (hl) inc hl ld h, (hl) ld l, a - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- (HL) - + __LOADF: ; Loads a 40 bits FP number from address pointed by HL - ld a, (hl) + ld a, (hl) inc hl ld e, (hl) inc hl @@ -281,77 +281,77 @@ __LOADF: ; Loads a 40 bits FP number from address pointed by HL inc hl ld b, (hl) ret - + #line 7 "ploadf.asm" - + __PLOADF: push ix pop hl add hl, de jp __LOADF - + #line 144 "pooky0.bas" #line 1 "subf.asm" - - - + + + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) - + ; All of them uses A EDCB registers as 1st paramter. ; For binary operators, the 2n operator must be pushed into the ; stack, in the order A DE BC. ; ; Uses CALLEE convention ; ------------------------------------------------------------- - - + + __SUBF: ; Subtraction call __FPSTACK_PUSH2 ; ENTERS B, A - + ; ------------- ROM SUB rst 28h defb 01h ; EXCHANGE defb 03h ; SUB defb 38h; ; END CALC - + jp __FPSTACK_POP - + #line 145 "pooky0.bas" #line 1 "u32tofreg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "u32tofreg.asm" __I8TOFREG: ld l, a @@ -360,35 +360,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -396,20 +396,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -417,32 +417,32 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 146 "pooky0.bas" - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/print.asm b/tests/functional/print.asm index 88e6fd1c5..e7efe354e 100644 --- a/tests/functional/print.asm +++ b/tests/functional/print.asm @@ -65,17 +65,17 @@ __LABEL0: DEFW 0001h DEFB 33h #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -83,46 +83,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -135,43 +135,43 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -179,12 +179,12 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -192,51 +192,51 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "in_screen.asm" - + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -245,17 +245,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -263,26 +263,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -296,45 +296,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -345,28 +345,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -374,28 +374,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -404,83 +404,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -489,32 +489,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -524,7 +524,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -532,20 +532,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -555,7 +555,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -566,19 +566,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -588,7 +588,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -599,19 +599,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -621,7 +621,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -634,22 +634,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -658,79 +658,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -739,75 +739,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -817,7 +817,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -829,16 +829,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -852,49 +852,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -905,17 +905,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -928,27 +928,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -956,10 +956,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -976,80 +976,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1066,8 +1066,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1091,17 +1091,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1112,7 +1112,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1122,21 +1122,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1155,9 +1155,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1182,35 +1182,35 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 52 "print.bas" #line 1 "print_eol_attr.asm" - + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes - - - - + + + + PRINT_EOL_ATTR: call PRINT_EOL jp COPY_ATTR #line 53 "print.bas" #line 1 "printf.asm" - + #line 1 "printstr.asm" - - - - + + + + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1218,25 +1218,25 @@ PRINT_EOL_ATTR: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1245,41 +1245,41 @@ PRINT_EOL_ATTR: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1287,25 +1287,25 @@ PRINT_EOL_ATTR: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1314,39 +1314,39 @@ PRINT_EOL_ATTR: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -1354,56 +1354,56 @@ PRINT_EOL_ATTR: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -1412,57 +1412,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -1471,47 +1471,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -1521,51 +1521,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 5 "printstr.asm" - + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1574,43 +1574,43 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 2 "printf.asm" #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -1626,68 +1626,68 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 3 "printf.asm" - - + + __PRINTF: ; Prints a Fixed point Number stored in C ED LH PROC - + LOCAL RECLAIM2 LOCAL STK_END STK_END EQU 5C65h - + ld hl, (ATTR_T) push hl ; Saves ATTR_T since BUG ROM changes it - + ld hl, (STK_END) push hl ; Stores STK_END - + call __FPSTACK_PUSH ; Push number into stack rst 28h ; # Rom Calculator defb 2Eh ; # STR$(x) defb 38h ; # END CALC call __FPSTACK_POP ; Recovers string parameters to A ED CB - + pop hl ld (STK_END), hl ; Balance STK_END to avoid STR$ bug - + pop hl ld (ATTR_T), hl ; Restores ATTR_T - + ex de, hl ; String position now in HL - + push bc xor a ; Avoid the str to be FREED from heap call __PRINT_STR - pop bc + pop bc inc bc - + jp RECLAIM2 ; Frees TMP Memory - + RECLAIM2 EQU 19E8h - + ENDP - + #line 54 "print.bas" #line 1 "printf16.asm" - + #line 1 "printnum.asm" - - - - + + + + __PRINTU_START: PROC - + LOCAL __PRINTU_CONT - + ld a, b or a jp nz, __PRINTU_CONT - + ld a, '0' jp __PRINT_DIGIT - - + + __PRINTU_CONT: pop af push bc @@ -1695,33 +1695,33 @@ __PRINTU_CONT: pop bc djnz __PRINTU_CONT ret - + ENDP - - + + __PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers ld a, '-' jp __PRINT_DIGIT - + __PRINT_DIGIT EQU __PRINTCHAR ; PRINTS the char in A register, and puts its attrs - - + + #line 2 "printf16.asm" #line 1 "printi16.asm" - - + + #line 1 "div16.asm" - - ; 16 bit division and modulo functions + + ; 16 bit division and modulo functions ; for both signed and unsigned values - + #line 1 "neg16.asm" - + ; Negates HL value (16 bit) __ABS16: bit 7, h ret z - + __NEGHL: ld a, l ; HL = -HL cpl @@ -1731,23 +1731,23 @@ __NEGHL: ld h, a inc hl ret - + #line 5 "div16.asm" - + __DIVU16: ; 16 bit unsigned division ; HL = Dividend, Stack Top = Divisor - + ; -- OBSOLETE ; Now uses FASTCALL convention ; ex de, hl ; pop hl ; Return address ; ex (sp), hl ; CALLEE Convention - + __DIVU16_FAST: ld a, h ld c, l ld hl, 0 ld b, 16 - + __DIV16LOOP: sll c rla @@ -1756,46 +1756,46 @@ __DIV16LOOP: jr nc, __DIV16NOADD add hl,de dec c - + __DIV16NOADD: djnz __DIV16LOOP - + ex de, hl ld h, a ld l, c - + ret ; HL = quotient, DE = Mudulus - - - + + + __MODU16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVU16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - - + + __DIVI16: ; 16 bit signed division ; --- The following is OBSOLETE --- ; ex de, hl ; pop hl ; ex (sp), hl ; CALLEE Convention - + __DIVI16_FAST: ld a, d xor h ex af, af' ; BIT 7 of a contains result - + bit 7, d ; DE is negative? - jr z, __DIVI16A - + jr z, __DIVI16A + ld a, e ; DE = -DE cpl ld e, a @@ -1803,209 +1803,209 @@ __DIVI16_FAST: cpl ld d, a inc de - + __DIVI16A: bit 7, h ; HL is negative? call nz, __NEGHL - + __DIVI16B: call __DIVU16_FAST ex af, af' - - or a + + or a ret p ; return if positive jp __NEGHL - - + + __MODI16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVI16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - + #line 3 "printi16.asm" - - - + + + __PRINTI16: ; Prints a 16bits signed in HL ; Converts 16 to 32 bits PROC - + LOCAL __PRINTU_LOOP ld a, h or a - + jp p, __PRINTU16 - + call __PRINT_MINUS call __NEGHL - + __PRINTU16: - + ld b, 0 __PRINTU_LOOP: ld a, h or l jp z, __PRINTU_START - + push bc ld de, 10 call __DIVU16_FAST ; Divides by DE. DE = MODULUS at exit. Since < 256, E = Modulus pop bc - + ld a, e or '0' ; Stores ASCII digit (must be print in reversed order) push af inc b jp __PRINTU_LOOP ; Uses JP in loops - + ENDP - + #line 3 "printf16.asm" #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 4 "printf16.asm" - + __PRINTF16: ; Prints a 32bit 16.16 fixed point number PROC - + LOCAL __PRINT_FIX_LOOP LOCAL __PRINTF16_2 - - bit 7, d + + bit 7, d jr z, __PRINTF16_2 call __NEG32 call __PRINT_MINUS - + __PRINTF16_2: push hl ex de, hl call __PRINTU16 ; Prints integer part pop hl - + ld a, h or l ret z ; Returns if integer - + push hl ld a, '.' call __PRINT_DIGIT ; Prints decimal point pop hl - + __PRINT_FIX_LOOP: ld a, h or l ret z ; Returns if no more decimals - + xor a ld d, h ld e, l ; Fast NUM * 10 multiplication - add hl, hl ; + add hl, hl ; adc a, a ; AHL = AHL * 2 (= X * 2) - add hl, hl ; + add hl, hl ; adc a, a ; AHL = AHL * 2 (= X * 4) - - add hl, de ; + + add hl, de ; adc a, 0 ; AHL = AHL + DE (= X * 5) add hl, hl adc a, a ; AHL = AHL * 2 (= X * 10) - + push hl or '0' call __PRINT_DIGIT pop hl jp __PRINT_FIX_LOOP - + ENDP - + #line 55 "print.bas" - + #line 1 "printi8.asm" - - + + #line 1 "div8.asm" - + ; -------------------------------- -__DIVU8: ; 8 bit unsigned integer division +__DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A pop hl ; -------------------------------- ex (sp), hl ; CALLEE - + __DIVU8_FAST: ; Does A / H ld l, h ld h, a ; At this point do H / L - + ld b, 8 xor a ; A = 0, Carry Flag = 0 - + __DIV8LOOP: - sla h - rla - cp l + sla h + rla + cp l jr c, __DIV8NOSUB - sub l - inc h - -__DIV8NOSUB: + sub l + inc h + +__DIV8NOSUB: djnz __DIV8LOOP - + ld l, a ; save remainder - ld a, h ; - - ret ; a = Quotient, - - + ld a, h ; + + ret ; a = Quotient, + + ; -------------------------------- __DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A pop hl ; -------------------------------- ex (sp), hl - + __DIVI8_FAST: ld e, a ; store operands for later ld c, h - + or a ; negative? jp p, __DIV8A neg ; Make it positive - + __DIV8A: ex af, af' ld a, h @@ -2013,99 +2013,99 @@ __DIV8A: jp p, __DIV8B neg ld h, a ; make it positive - + __DIV8B: ex af, af' - + call __DIVU8_FAST - + ld a, c xor l ; bit 7 of A = 1 if result is negative - + ld a, h ; Quotient - ret p ; return if positive - + ret p ; return if positive + neg ret - - + + __MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) pop hl ex (sp), hl ; CALLEE - + __MODU8_FAST: ; __FASTCALL__ entry call __DIVU8_FAST ld a, l ; Remainder - + ret ; a = Modulus - - + + __MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) pop hl ex (sp), hl ; CALLEE - + __MODI8_FAST: ; __FASTCALL__ entry call __DIVI8_FAST ld a, l ; remainder - + ret ; a = Modulus - + #line 3 "printi8.asm" - + __PRINTI8: ; Prints an 8 bits number in Accumulator (A) ; Converts 8 to 32 bits or a jp p, __PRINTU8 - + push af call __PRINT_MINUS pop af neg - + __PRINTU8: PROC - + LOCAL __PRINTU_LOOP - + ld b, 0 ; Counter - + __PRINTU_LOOP: or a jp z, __PRINTU_START - + push bc ld h, 10 call __DIVU8_FAST ; Divides by 10. D'E'H'L' contains modulo (L' since < 10) pop bc - + ld a, l or '0' ; Stores ASCII digit (must be print in reversed order) push af ld a, h inc b jp __PRINTU_LOOP ; Uses JP in loops - + ENDP - + #line 57 "print.bas" - + #line 1 "printu16.asm" - - - + + + #line 59 "print.bas" #line 1 "printu8.asm" - - - + + + #line 60 "print.bas" #line 1 "strcat.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -2113,25 +2113,25 @@ __PRINTU_LOOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -2140,40 +2140,40 @@ __PRINTU_LOOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - - + + + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -2185,27 +2185,27 @@ __PRINTU_LOOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -2217,7 +2217,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -2225,15 +2225,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -2258,14 +2258,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -2273,114 +2273,114 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "strcat.asm" #line 1 "strlen.asm" - + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL - + __STRLEN: ; Direct FASTCALL entry ld a, h or l ret z - + ld a, (hl) inc hl ld h, (hl) ; LEN(str) in HL ld l, a ret - - + + #line 3 "strcat.asm" - + __ADDSTR: ; Implements c$ = a$ + b$ ; hl = &a$, de = &b$ (pointers) - - + + __STRCAT2: ; This routine creates a new string in dynamic space ; making room for it. Then copies a$ + b$ into it. ; HL = a$, DE = b$ - + PROC - + LOCAL __STR_CONT LOCAL __STRCATEND - + push hl call __STRLEN ld c, l ld b, h ; BC = LEN(a$) ex (sp), hl ; (SP) = LEN (a$), HL = a$ push hl ; Saves pointer to a$ - + inc bc inc bc ; +2 bytes to store length - + ex de, hl push hl call __STRLEN ; HL = len(b$) - + add hl, bc ; Total str length => 2 + len(a$) + len(b$) - + ld c, l ld b, h ; BC = Total str length + 2 - call __MEM_ALLOC - pop de ; HL = c$, DE = b$ - + call __MEM_ALLOC + pop de ; HL = c$, DE = b$ + ex de, hl ; HL = b$, DE = c$ - ex (sp), hl ; HL = a$, (SP) = b$ - + ex (sp), hl ; HL = a$, (SP) = b$ + exx - pop de ; D'E' = b$ + pop de ; D'E' = b$ exx - + pop bc ; LEN(a$) - + ld a, d or e ret z ; If no memory: RETURN - + __STR_CONT: push de ; Address of c$ - + ld a, h or l jr nz, __STR_CONT1 ; If len(a$) != 0 do copy - + ; a$ is NULL => uses HL = DE for transfer ld h, d ld l, e ld (hl), a ; This will copy 00 00 at (DE) location - inc de ; + inc de ; dec bc ; Ensure BC will be set to 1 in the next step - + __STR_CONT1: ; Copies a$ (HL) into c$ (DE) - inc bc + inc bc inc bc ; BC = BC + 2 ldir ; MEMCOPY: c$ = a$ pop hl ; HL = c$ - + exx push de ; Recovers b$; A ex hl,hl' would be very handy exx - - pop de ; DE = b$ - + + pop de ; DE = b$ + __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ; NOTE: Both DE, BC and AF are modified and lost ; Returns HL (pointer to a$) @@ -2388,50 +2388,50 @@ __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ld a, d or e ret z ; Returns if de is NULL (nothing to copy) - + push hl ; Saves HL to return it later - + ld c, (hl) inc hl ld b, (hl) inc hl add hl, bc ; HL = end of (a$) string ; bc = len(a$) push bc ; Saves LEN(a$) for later - + ex de, hl ; DE = end of string (Begin of copy addr) ld c, (hl) inc hl ld b, (hl) ; BC = len(b$) - + ld a, b or c jr z, __STRCATEND; Return if len(b$) == 0 - + push bc ; Save LEN(b$) inc hl ; Skip 2nd byte of len(b$) ldir ; Concatenate b$ - + pop bc ; Recovers length (b$) pop hl ; Recovers length (a$) add hl, bc ; HL = LEN(a$) + LEN(b$) = LEN(a$+b$) ex de, hl ; DE = LEN(a$+b$) pop hl - + ld (hl), e ; Updates new LEN and return inc hl ld (hl), d dec hl ret - + __STRCATEND: pop hl ; Removes Len(a$) pop hl ; Restores original HL, so HL = a$ ret - + ENDP - + #line 61 "print.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/print42.asm b/tests/functional/print42.asm index de632bbe7..110b49251 100644 --- a/tests/functional/print42.asm +++ b/tests/functional/print42.asm @@ -472,10 +472,10 @@ _print42__leave: exx ret #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -483,25 +483,25 @@ _print42__leave: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -510,41 +510,41 @@ _print42__leave: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -552,25 +552,25 @@ _print42__leave: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -579,39 +579,39 @@ _print42__leave: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -619,56 +619,56 @@ _print42__leave: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -677,57 +677,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -736,47 +736,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -786,11 +786,11 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 460 "print42.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/print64.asm b/tests/functional/print64.asm index 09523c5c9..e916b59c2 100644 --- a/tests/functional/print64.asm +++ b/tests/functional/print64.asm @@ -301,10 +301,10 @@ _print64__leave: exx ret #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -312,25 +312,25 @@ _print64__leave: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -339,41 +339,41 @@ _print64__leave: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -381,25 +381,25 @@ _print64__leave: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -408,39 +408,39 @@ _print64__leave: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -448,56 +448,56 @@ _print64__leave: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -506,57 +506,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -565,47 +565,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -615,11 +615,11 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 289 "print64.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/randomize.asm b/tests/functional/randomize.asm index c100b50b6..298dcf688 100644 --- a/tests/functional/randomize.asm +++ b/tests/functional/randomize.asm @@ -33,27 +33,27 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "random.asm" - + ; RANDOM functions - + RANDOMIZE: ; Randomize with 32 bit seed in DE HL ; if SEED = 0, calls ROM to take frames as seed PROC - + LOCAL TAKE_FRAMES LOCAL FRAMES - + ld a, h or l or d or e jr z, TAKE_FRAMES - + ld (RANDOM_SEED_LOW), hl ld (RANDOM_SEED_HIGH), de ret - + TAKE_FRAMES: ; Takes the seed from frames ld hl, (FRAMES) @@ -61,18 +61,18 @@ TAKE_FRAMES: ld hl, (FRAMES + 2) ld (RANDOM_SEED_HIGH), hl ret - + FRAMES EQU 23672 ENDP - + RANDOM_SEED_HIGH EQU RAND+6 ; RANDOM seed, 16 higher bits RANDOM_SEED_LOW EQU 23670 ; RANDOM seed, 16 lower bits - - + + RAND: PROC LOCAL RAND_LOOP - ld b, 4 + ld b, 4 RAND_LOOP: ld hl,(RANDOM_SEED_LOW) ; xz -> yw ld de,0C0DEh ; yw -> zt @@ -104,30 +104,30 @@ RAND_LOOP: ld h, a ret ENDP - + RND: ; Returns a FLOATING point integer ; using RAND as a mantissa PROC LOCAL RND_LOOP - + call RAND ; BC = HL since ZX BASIC uses ED CB A registers for FP ld b, h ld c, l - + ld a, e or d or c or b ret z ; Returns 0 if BC=DE=0 - + ; We already have a random 32 bit mantissa in ED CB ; From 0001h to FFFFh - + ld l, 81h ; Exponent ; At this point we have [0 .. 1) FP number; - + ; Now we must shift mantissa left until highest bit goes into carry ld a, e ; Use A register for rotating E faster (using RLA instead of RL E) RND_LOOP: @@ -137,22 +137,22 @@ RND_LOOP: rl d rla jp nc, RND_LOOP - + ; Now undo last mantissa left-shift once ccf ; Clears carry to insert a 0 bit back into mantissa -> positive FP number rra - rr d + rr d rr c rr b - + ld e, a ; E must have the highest byte ld a, l ; exponent in A ret - + ENDP - + #line 24 "randomize.bas" - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/read.asm b/tests/functional/read.asm index 82d634059..3ff97e089 100644 --- a/tests/functional/read.asm +++ b/tests/functional/read.asm @@ -62,12 +62,12 @@ __LABEL0: DEFB 61h DEFB 6Eh #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -75,25 +75,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -102,51 +102,51 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -154,12 +154,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -167,7 +167,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -175,10 +175,10 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -186,25 +186,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -213,39 +213,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -253,57 +253,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -315,27 +315,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -347,7 +347,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -355,15 +355,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -388,14 +388,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -403,25 +403,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -430,30 +430,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -461,14 +461,14 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 50 "read.bas" #line 1 "read_restore.asm" - + ;; This implements READ & RESTORE functions ;; Reads a new element from the DATA Address code ;; Updates the DATA_ADDR read ptr for the next read - + ;; Data codification is 1 byte for type followed by data bytes ;; Byte type is encoded as follows - + ;; 00: End of data ;; 01: String ;; 02: Byte @@ -479,21 +479,21 @@ __LOADSTR: ; __FASTCALL__ entry ;; 07: ULong ;; 08: Fixed ;; 09: Float - + ;; bit7 is set for a parameter-less function ;; In that case, the next two bytes are the ptr of the function to jump - - - + + + #line 1 "iload32.asm" - + ; __FASTCALL__ routine which ; loads a 32 bits integer into DE,HL ; stored at position pointed by POINTER HL ; DE,HL <-- (HL) - + __ILOAD32: - ld e, (hl) + ld e, (hl) inc hl ld d, (hl) inc hl @@ -503,28 +503,28 @@ __ILOAD32: ld l, a ex de, hl ret - + #line 25 "read_restore.asm" #line 1 "iloadf.asm" - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- ((HL)) - + __ILOADF: ld a, (hl) inc hl ld h, (hl) ld l, a - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- (HL) - + __LOADF: ; Loads a 40 bits FP number from address pointed by HL - ld a, (hl) + ld a, (hl) inc hl ld e, (hl) inc hl @@ -534,57 +534,57 @@ __LOADF: ; Loads a 40 bits FP number from address pointed by HL inc hl ld b, (hl) ret - + #line 26 "read_restore.asm" #line 1 "ftof16reg.asm" - + #line 1 "ftou32reg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "ftou32reg.asm" - + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) PROC - + LOCAL __IS_FLOAT - + or a - jr nz, __IS_FLOAT + jr nz, __IS_FLOAT ; Here if it is a ZX ROM Integer - + ld h, c ld l, d ld a, e ; Takes sign: FF = -, 0 = + @@ -592,67 +592,67 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS inc a jp z, __NEG32 ; Negates if negative ret - + __IS_FLOAT: ; Jumps here if it is a true floating point number - ld h, e + ld h, e push hl ; Stores it for later (Contains Sign in H) - + push de push bc - + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + ;ld a, c ; Get exponent sub 128 ; Exponent -= 128 jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 - + __FTOU32REG_LOOP: exx ; Shift C'B' E'D' << 1, output bit stays in Carry sla d rl e rl b rl c - + exx ; Shift DEHL << 1, inserting the carry on the right rl l rl h rl e rl d - + djnz __FTOU32REG_LOOP - + __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative jp m, __NEG32 ; Negates DEHL - + ret - + ENDP - - + + __FTOU8: ; Converts float in C ED LH to Unsigned byte in A call __FTOU32REG ld a, l ret - + #line 2 "ftof16reg.asm" - + __FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal ; Input FP number in A EDCB (A exponent, EDCB mantissa) - + ld l, a ; Saves exponent for later or d or e @@ -660,43 +660,43 @@ __FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal or c ld h, e ret z ; Return if ZERO - + push hl ; Stores it for later (Contains sign in H, exponent in L) - + push de - push bc - + push bc + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + pop bc - + ld a, c ; Get exponent sub 112 ; Exponent -= 128 + 16 - + push bc ; Saves sign in b again - + jp z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jp c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 + 16 (we need to shift 16 bit more) jp __FTOU32REG_LOOP ; proceed as an u32 integer - + #line 27 "read_restore.asm" #line 1 "f16tofreg.asm" - - + + #line 1 "u32tofreg.asm" - - + + __I8TOFREG: ld l, a rlca @@ -704,35 +704,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -740,20 +740,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -761,53 +761,53 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 3 "f16tofreg.asm" - + __F16TOFREG: ; Converts a 16.16 signed fixed point (stored in DEHL) ; to a Floating Point Number returned in (C ED CB) PROC - + LOCAL __F16TOFREG2 - + ld a, d or a ; Test sign - + jp p, __F16TOFREG2 ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __F16TOFREG2 ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - - + + __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in C DE HL - + ld a, d or e or h @@ -815,29 +815,29 @@ __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ld b, h ld c, l ret z ; Return 00 0000 0000 if 0 - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 112 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c jp __U32TOFREG_LOOP ; Proceed as an integer - + ENDP - + #line 28 "read_restore.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -845,25 +845,25 @@ __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -872,38 +872,38 @@ __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -912,57 +912,57 @@ __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -971,47 +971,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -1021,30 +1021,30 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 29 "read_restore.asm" - - - - - - - - - - - - + + + + + + + + + + + + ;; Updates restore point to the given HL mem. address __RESTORE: PROC LOCAL __DATA_ADDR - + ld (__DATA_ADDR), hl ret - + ;; Reads a value from the DATA mem area and updates __DATA_ADDR ptr to the ;; next item. On Out Of Data, restarts ;; @@ -1056,7 +1056,7 @@ __READ: LOCAL _from_i16, _from_u16 LOCAL _from_i32, _from_u32 LOCAL _from_fixed, __data_error - + push af ; type of data to read ld hl, (__DATA_ADDR) read_restart: @@ -1064,7 +1064,7 @@ read_restart: or a ; 0 => OUT of data jr nz, cont ;; Signals out of data - + ld hl, __DATA__0 ld (__DATA_ADDR), hl jr read_restart ; Start again @@ -1084,7 +1084,7 @@ cont2: ld de, dynamic_cast push de ; ret address jp (hl) ; "call (hl)" - + ;; Now tries to convert the given result to the expected type or raise an error dynamic_cast: exx @@ -1099,13 +1099,13 @@ dynamic_cast: ;; yes, they are ex af, af' ret - + dynamic_cast2: cp 1 ; Requested a number, but read a string? jr nz, dynamic_cast3 call __MEM_FREE ; Frees str from memory jr __data_error - + dynamic_cast3: exx ld b, a ; Read type @@ -1130,7 +1130,7 @@ dynamic_cast3: ld a, c ; Requested type exx ret - + __data_error: ;; When a data is read, but cannot be converted to the requested type ;; that is, the user asked for a string and we read a number or vice versa @@ -1144,7 +1144,7 @@ __data_error: ld b, a ld c, a ret - + _decode_table: dw _from_i8 dw _from_u8 @@ -1153,13 +1153,13 @@ _decode_table: dw _from_i32 dw _from_u32 dw _from_fixed - + _from_i8: cp 4 jr nc, promote_to_i16 ex af, af' ret ;; Was from Byte to Ubyte - + promote_to_i16: ex af, af' ld l, a @@ -1168,14 +1168,14 @@ promote_to_i16: ld h, a ; copy sgn to h ex af, af' jr _before_from_i16 - + _from_u8: ex af, af' ld l, a ld h, 0 ex af, af' ;; Promoted to i16 - + _before_from_i16: _from_i16: cp 6 @@ -1206,7 +1206,7 @@ _from_fixed: ;; From fixed to float _from_u16: ld de, 0 ; HL 0x0000 => 32 bits jp _from_i32 - + dynamic_cast4: ;; The user type is "shorter" than the read one cp 8 ;; required type @@ -1214,7 +1214,7 @@ dynamic_cast4: ex af, af' exx ;; Ok, we must convert from float to f16 jp __FTOF16REG - + before_to_int: ld a, b ;; read type cp 8 ;; @@ -1242,7 +1242,7 @@ coerce_to_int2: ; At this point we have an u/integer in hl ret nc ; Already done. Return the result ld a, l ; Truncate to byte ret - + no_func: exx ld de, dynamic_cast @@ -1261,7 +1261,7 @@ no_func: exx inc hl ret ; jp (sp) => jump to table[a - 1] - + table: LOCAL __01_decode_string LOCAL __02_decode_byte @@ -1272,7 +1272,7 @@ table: LOCAL __07_decode_ulong LOCAL __08_decode_fixed LOCAL __09_decode_float - + ;; 1 -> Decode string ;; 2, 3 -> Decode Byte, UByte ;; 4, 5 -> Decode Integer, UInteger @@ -1288,7 +1288,7 @@ table: dw __07_decode_ulong dw __08_decode_fixed dw __09_decode_float - + __01_decode_string: ld e, (hl) inc hl @@ -1297,14 +1297,14 @@ __01_decode_string: ld (__DATA_ADDR), hl ;; Store address of next DATA ex de, hl jp __LOADSTR - + __02_decode_byte: __03_decode_ubyte: ld a, (hl) inc hl ld (__DATA_ADDR), hl ret - + __04_decode_integer: __05_decode_uinteger: ld e, (hl) @@ -1314,7 +1314,7 @@ __05_decode_uinteger: ld (__DATA_ADDR), hl ex de, hl ret - + __06_decode_long: __07_decode_ulong: __08_decode_fixed: @@ -1326,30 +1326,30 @@ __08_decode_fixed: inc bc ld (__DATA_ADDR), bc jp __ILOAD32 - + __09_decode_float: call __LOADF inc hl ld (__DATA_ADDR), hl ld h, a ; returns A in H; sets A free ret - + __DATA_ADDR: ;; Stores current DATA ptr dw __DATA__0 ENDP - - - - - - - - - - + + + + + + + + + + #line 51 "read.bas" #line 1 "storef.asm" - + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -1357,7 +1357,7 @@ __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory pop hl ; HL <- IX add hl, de ; HL <- IX + HL pop de - + __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register ex af, af' ld a, (hl) @@ -1365,7 +1365,7 @@ __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address ld h, (hl) ld l, a ; HL = (HL) ex af, af' - + __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), a inc hl @@ -1377,9 +1377,9 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL inc hl ld (hl), b ret - + #line 52 "read.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00, 00 diff --git a/tests/functional/read10.asm b/tests/functional/read10.asm index e88be16e6..774133f6b 100644 --- a/tests/functional/read10.asm +++ b/tests/functional/read10.asm @@ -134,40 +134,40 @@ __DATA__0: __DATA__END: DEFB 00h #line 1 "mulf.asm" - + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -183,7 +183,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 2 "mulf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) ; All of them uses A EDCB registers as 1st paramter. @@ -192,45 +192,45 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; ; Uses CALLEE convention ; ------------------------------------------------------------- - + __MULF: ; Multiplication call __FPSTACK_PUSH2 - + ; ------------- ROM MUL rst 28h - defb 04h ; + defb 04h ; defb 38h; ; END CALC - + jp __FPSTACK_POP - + #line 121 "read10.bas" #line 1 "ploadf.asm" - + ; Parameter / Local var load ; A => Offset ; IX = Stack Frame ; RESULT: HL => IX + DE - + #line 1 "iloadf.asm" - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- ((HL)) - + __ILOADF: ld a, (hl) inc hl ld h, (hl) ld l, a - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- (HL) - + __LOADF: ; Loads a 40 bits FP number from address pointed by HL - ld a, (hl) + ld a, (hl) inc hl ld e, (hl) inc hl @@ -240,23 +240,23 @@ __LOADF: ; Loads a 40 bits FP number from address pointed by HL inc hl ld b, (hl) ret - + #line 7 "ploadf.asm" - + __PLOADF: push ix pop hl add hl, de jp __LOADF - + #line 122 "read10.bas" #line 1 "pow.asm" - - - + + + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) - + ; All of them uses A EDCB registers as 1st paramter. ; For binary operators, the 2n operator must be pushed into the ; stack, in the order A DE BC. @@ -267,35 +267,35 @@ __PLOADF: ; 1 st parameter is the BASE (A ED CB) ; 2 nd parameter (Top of the stack) is Exponent ; ------------------------------------------------------------- - + __POW: ; Exponentiation PROC - + call __FPSTACK_PUSH2 - + ; ------------- ROM POW rst 28h defb 01h ; Exchange => 1, Base defb 06h ; POW defb 38h; ; END CALC - + jp __FPSTACK_POP - + ENDP - + #line 123 "read10.bas" #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -303,46 +303,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -355,43 +355,43 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -399,12 +399,12 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -412,51 +412,51 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "in_screen.asm" - + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -465,17 +465,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -483,26 +483,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -516,45 +516,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -565,28 +565,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -594,28 +594,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -624,83 +624,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -709,32 +709,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -744,7 +744,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -752,20 +752,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -775,7 +775,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -786,19 +786,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -808,7 +808,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -819,19 +819,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -841,7 +841,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -854,22 +854,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -878,79 +878,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -959,75 +959,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -1037,7 +1037,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -1049,16 +1049,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1072,49 +1072,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1125,17 +1125,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1148,27 +1148,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1176,10 +1176,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1196,80 +1196,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1286,8 +1286,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1311,17 +1311,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1332,7 +1332,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1342,21 +1342,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1375,9 +1375,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1402,23 +1402,23 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 124 "read10.bas" #line 1 "printf.asm" - + #line 1 "printstr.asm" - - - - + + + + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1426,25 +1426,25 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1453,41 +1453,41 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1495,25 +1495,25 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1522,39 +1522,39 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -1562,56 +1562,56 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -1620,57 +1620,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -1679,47 +1679,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -1729,51 +1729,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 5 "printstr.asm" - + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1782,62 +1782,62 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 2 "printf.asm" - - - + + + __PRINTF: ; Prints a Fixed point Number stored in C ED LH PROC - + LOCAL RECLAIM2 LOCAL STK_END STK_END EQU 5C65h - + ld hl, (ATTR_T) push hl ; Saves ATTR_T since BUG ROM changes it - + ld hl, (STK_END) push hl ; Stores STK_END - + call __FPSTACK_PUSH ; Push number into stack rst 28h ; # Rom Calculator defb 2Eh ; # STR$(x) defb 38h ; # END CALC call __FPSTACK_POP ; Recovers string parameters to A ED CB - + pop hl ld (STK_END), hl ; Balance STK_END to avoid STR$ bug - + pop hl ld (ATTR_T), hl ; Restores ATTR_T - + ex de, hl ; String position now in HL - + push bc xor a ; Avoid the str to be FREED from heap call __PRINT_STR - pop bc + pop bc inc bc - + jp RECLAIM2 ; Frees TMP Memory - + RECLAIM2 EQU 19E8h - + ENDP - + #line 125 "read10.bas" #line 1 "pstoref.asm" - + ; Stores FP number in A ED CB at location HL+IX ; HL = Offset ; IX = Stack Frame ; A ED CB = FP Number - + #line 1 "storef.asm" - + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -1845,7 +1845,7 @@ __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory pop hl ; HL <- IX add hl, de ; HL <- IX + HL pop de - + __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register ex af, af' ld a, (hl) @@ -1853,7 +1853,7 @@ __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address ld h, (hl) ld l, a ; HL = (HL) ex af, af' - + __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), a inc hl @@ -1865,9 +1865,9 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL inc hl ld (hl), b ret - + #line 7 "pstoref.asm" - + ; Stored a float number in A ED CB into the address pointed by IX + HL __PSTOREF: push de @@ -1875,19 +1875,19 @@ __PSTOREF: push ix pop hl ; HL <- IX add hl, de ; HL <- IX + DE - pop de + pop de jp __STOREF - + #line 126 "read10.bas" #line 1 "read_restore.asm" - + ;; This implements READ & RESTORE functions ;; Reads a new element from the DATA Address code ;; Updates the DATA_ADDR read ptr for the next read - + ;; Data codification is 1 byte for type followed by data bytes ;; Byte type is encoded as follows - + ;; 00: End of data ;; 01: String ;; 02: Byte @@ -1898,18 +1898,18 @@ __PSTOREF: ;; 07: ULong ;; 08: Fixed ;; 09: Float - + ;; bit7 is set for a parameter-less function ;; In that case, the next two bytes are the ptr of the function to jump - - + + #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1917,25 +1917,25 @@ __PSTOREF: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1944,40 +1944,40 @@ __PSTOREF: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - - + + + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -1989,27 +1989,27 @@ __PSTOREF: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -2021,7 +2021,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -2029,15 +2029,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -2062,14 +2062,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -2077,25 +2077,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -2104,30 +2104,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -2135,14 +2135,14 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 24 "read_restore.asm" #line 1 "iload32.asm" - + ; __FASTCALL__ routine which ; loads a 32 bits integer into DE,HL ; stored at position pointed by POINTER HL ; DE,HL <-- (HL) - + __ILOAD32: - ld e, (hl) + ld e, (hl) inc hl ld d, (hl) inc hl @@ -2152,58 +2152,58 @@ __ILOAD32: ld l, a ex de, hl ret - + #line 25 "read_restore.asm" - + #line 1 "ftof16reg.asm" - + #line 1 "ftou32reg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "ftou32reg.asm" - + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) PROC - + LOCAL __IS_FLOAT - + or a - jr nz, __IS_FLOAT + jr nz, __IS_FLOAT ; Here if it is a ZX ROM Integer - + ld h, c ld l, d ld a, e ; Takes sign: FF = -, 0 = + @@ -2211,67 +2211,67 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS inc a jp z, __NEG32 ; Negates if negative ret - + __IS_FLOAT: ; Jumps here if it is a true floating point number - ld h, e + ld h, e push hl ; Stores it for later (Contains Sign in H) - + push de push bc - + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + ;ld a, c ; Get exponent sub 128 ; Exponent -= 128 jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 - + __FTOU32REG_LOOP: exx ; Shift C'B' E'D' << 1, output bit stays in Carry sla d rl e rl b rl c - + exx ; Shift DEHL << 1, inserting the carry on the right rl l rl h rl e rl d - + djnz __FTOU32REG_LOOP - + __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative jp m, __NEG32 ; Negates DEHL - + ret - + ENDP - - + + __FTOU8: ; Converts float in C ED LH to Unsigned byte in A call __FTOU32REG ld a, l ret - + #line 2 "ftof16reg.asm" - + __FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal ; Input FP number in A EDCB (A exponent, EDCB mantissa) - + ld l, a ; Saves exponent for later or d or e @@ -2279,43 +2279,43 @@ __FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal or c ld h, e ret z ; Return if ZERO - + push hl ; Stores it for later (Contains sign in H, exponent in L) - + push de - push bc - + push bc + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + pop bc - + ld a, c ; Get exponent sub 112 ; Exponent -= 128 + 16 - + push bc ; Saves sign in b again - + jp z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jp c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 + 16 (we need to shift 16 bit more) jp __FTOU32REG_LOOP ; proceed as an u32 integer - + #line 27 "read_restore.asm" #line 1 "f16tofreg.asm" - - + + #line 1 "u32tofreg.asm" - - + + __I8TOFREG: ld l, a rlca @@ -2323,35 +2323,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -2359,20 +2359,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -2380,53 +2380,53 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 3 "f16tofreg.asm" - + __F16TOFREG: ; Converts a 16.16 signed fixed point (stored in DEHL) ; to a Floating Point Number returned in (C ED CB) PROC - + LOCAL __F16TOFREG2 - + ld a, d or a ; Test sign - + jp p, __F16TOFREG2 ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __F16TOFREG2 ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - - + + __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in C DE HL - + ld a, d or e or h @@ -2434,45 +2434,45 @@ __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ld b, h ld c, l ret z ; Return 00 0000 0000 if 0 - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 112 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c jp __U32TOFREG_LOOP ; Proceed as an integer - + ENDP - + #line 28 "read_restore.asm" - - - - - - - - - - - - - + + + + + + + + + + + + + ;; Updates restore point to the given HL mem. address __RESTORE: PROC LOCAL __DATA_ADDR - + ld (__DATA_ADDR), hl ret - + ;; Reads a value from the DATA mem area and updates __DATA_ADDR ptr to the ;; next item. On Out Of Data, restarts ;; @@ -2484,7 +2484,7 @@ __READ: LOCAL _from_i16, _from_u16 LOCAL _from_i32, _from_u32 LOCAL _from_fixed, __data_error - + push af ; type of data to read ld hl, (__DATA_ADDR) read_restart: @@ -2492,7 +2492,7 @@ read_restart: or a ; 0 => OUT of data jr nz, cont ;; Signals out of data - + ld hl, __DATA__0 ld (__DATA_ADDR), hl jr read_restart ; Start again @@ -2512,7 +2512,7 @@ cont2: ld de, dynamic_cast push de ; ret address jp (hl) ; "call (hl)" - + ;; Now tries to convert the given result to the expected type or raise an error dynamic_cast: exx @@ -2527,13 +2527,13 @@ dynamic_cast: ;; yes, they are ex af, af' ret - + dynamic_cast2: cp 1 ; Requested a number, but read a string? jr nz, dynamic_cast3 call __MEM_FREE ; Frees str from memory jr __data_error - + dynamic_cast3: exx ld b, a ; Read type @@ -2558,7 +2558,7 @@ dynamic_cast3: ld a, c ; Requested type exx ret - + __data_error: ;; When a data is read, but cannot be converted to the requested type ;; that is, the user asked for a string and we read a number or vice versa @@ -2572,7 +2572,7 @@ __data_error: ld b, a ld c, a ret - + _decode_table: dw _from_i8 dw _from_u8 @@ -2581,13 +2581,13 @@ _decode_table: dw _from_i32 dw _from_u32 dw _from_fixed - + _from_i8: cp 4 jr nc, promote_to_i16 ex af, af' ret ;; Was from Byte to Ubyte - + promote_to_i16: ex af, af' ld l, a @@ -2596,14 +2596,14 @@ promote_to_i16: ld h, a ; copy sgn to h ex af, af' jr _before_from_i16 - + _from_u8: ex af, af' ld l, a ld h, 0 ex af, af' ;; Promoted to i16 - + _before_from_i16: _from_i16: cp 6 @@ -2634,7 +2634,7 @@ _from_fixed: ;; From fixed to float _from_u16: ld de, 0 ; HL 0x0000 => 32 bits jp _from_i32 - + dynamic_cast4: ;; The user type is "shorter" than the read one cp 8 ;; required type @@ -2642,7 +2642,7 @@ dynamic_cast4: ex af, af' exx ;; Ok, we must convert from float to f16 jp __FTOF16REG - + before_to_int: ld a, b ;; read type cp 8 ;; @@ -2670,7 +2670,7 @@ coerce_to_int2: ; At this point we have an u/integer in hl ret nc ; Already done. Return the result ld a, l ; Truncate to byte ret - + no_func: exx ld de, dynamic_cast @@ -2689,7 +2689,7 @@ no_func: exx inc hl ret ; jp (sp) => jump to table[a - 1] - + table: LOCAL __01_decode_string LOCAL __02_decode_byte @@ -2700,7 +2700,7 @@ table: LOCAL __07_decode_ulong LOCAL __08_decode_fixed LOCAL __09_decode_float - + ;; 1 -> Decode string ;; 2, 3 -> Decode Byte, UByte ;; 4, 5 -> Decode Integer, UInteger @@ -2716,7 +2716,7 @@ table: dw __07_decode_ulong dw __08_decode_fixed dw __09_decode_float - + __01_decode_string: ld e, (hl) inc hl @@ -2725,14 +2725,14 @@ __01_decode_string: ld (__DATA_ADDR), hl ;; Store address of next DATA ex de, hl jp __LOADSTR - + __02_decode_byte: __03_decode_ubyte: ld a, (hl) inc hl ld (__DATA_ADDR), hl ret - + __04_decode_integer: __05_decode_uinteger: ld e, (hl) @@ -2742,7 +2742,7 @@ __05_decode_uinteger: ld (__DATA_ADDR), hl ex de, hl ret - + __06_decode_long: __07_decode_ulong: __08_decode_fixed: @@ -2754,57 +2754,57 @@ __08_decode_fixed: inc bc ld (__DATA_ADDR), bc jp __ILOAD32 - + __09_decode_float: call __LOADF inc hl ld (__DATA_ADDR), hl ld h, a ; returns A in H; sets A free ret - + __DATA_ADDR: ;; Stores current DATA ptr dw __DATA__0 ENDP - - - - - - - - - - + + + + + + + + + + #line 127 "read10.bas" #line 1 "sin.asm" - - - + + + SIN: ; Computes SIN using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 1Fh defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 128 "read10.bas" #line 1 "tan.asm" - - - + + + TAN: ; Computes TAN using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 21h ; TAN defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 129 "read10.bas" - + ZXBASIC_USER_DATA: _v: DEFB 81h diff --git a/tests/functional/read12.asm b/tests/functional/read12.asm index af088e720..1dd1309d0 100644 --- a/tests/functional/read12.asm +++ b/tests/functional/read12.asm @@ -66,12 +66,12 @@ __LABEL0: DEFB 6Ch DEFB 61h #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -79,25 +79,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -106,51 +106,51 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -158,12 +158,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -171,7 +171,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -179,10 +179,10 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -190,25 +190,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -217,39 +217,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -257,57 +257,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -319,27 +319,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -351,7 +351,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -359,15 +359,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -392,14 +392,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -407,25 +407,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -434,30 +434,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -465,17 +465,17 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 53 "read12.bas" #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -483,46 +483,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -535,67 +535,67 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - - - + + + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -604,17 +604,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -622,26 +622,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -655,45 +655,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -704,28 +704,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -733,28 +733,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -763,83 +763,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -848,32 +848,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -883,7 +883,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -891,20 +891,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -914,7 +914,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -925,19 +925,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -947,7 +947,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -958,19 +958,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -980,7 +980,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -993,22 +993,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -1017,79 +1017,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -1098,75 +1098,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -1176,7 +1176,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -1188,16 +1188,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1211,49 +1211,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1264,17 +1264,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1287,27 +1287,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1315,10 +1315,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1335,80 +1335,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1425,8 +1425,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1450,17 +1450,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1471,7 +1471,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1481,21 +1481,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1514,9 +1514,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1541,31 +1541,31 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 54 "read12.bas" #line 1 "printi8.asm" - + #line 1 "printnum.asm" - - - - + + + + __PRINTU_START: PROC - + LOCAL __PRINTU_CONT - + ld a, b or a jp nz, __PRINTU_CONT - + ld a, '0' jp __PRINT_DIGIT - - + + __PRINTU_CONT: pop af push bc @@ -1573,63 +1573,63 @@ __PRINTU_CONT: pop bc djnz __PRINTU_CONT ret - + ENDP - - + + __PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers ld a, '-' jp __PRINT_DIGIT - + __PRINT_DIGIT EQU __PRINTCHAR ; PRINTS the char in A register, and puts its attrs - - + + #line 2 "printi8.asm" #line 1 "div8.asm" - + ; -------------------------------- -__DIVU8: ; 8 bit unsigned integer division +__DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A pop hl ; -------------------------------- ex (sp), hl ; CALLEE - + __DIVU8_FAST: ; Does A / H ld l, h ld h, a ; At this point do H / L - + ld b, 8 xor a ; A = 0, Carry Flag = 0 - + __DIV8LOOP: - sla h - rla - cp l + sla h + rla + cp l jr c, __DIV8NOSUB - sub l - inc h - -__DIV8NOSUB: + sub l + inc h + +__DIV8NOSUB: djnz __DIV8LOOP - + ld l, a ; save remainder - ld a, h ; - - ret ; a = Quotient, - - + ld a, h ; + + ret ; a = Quotient, + + ; -------------------------------- __DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A pop hl ; -------------------------------- ex (sp), hl - + __DIVI8_FAST: ld e, a ; store operands for later ld c, h - + or a ; negative? jp p, __DIV8A neg ; Make it positive - + __DIV8A: ex af, af' ld a, h @@ -1637,90 +1637,90 @@ __DIV8A: jp p, __DIV8B neg ld h, a ; make it positive - + __DIV8B: ex af, af' - + call __DIVU8_FAST - + ld a, c xor l ; bit 7 of A = 1 if result is negative - + ld a, h ; Quotient - ret p ; return if positive - + ret p ; return if positive + neg ret - - + + __MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) pop hl ex (sp), hl ; CALLEE - + __MODU8_FAST: ; __FASTCALL__ entry call __DIVU8_FAST ld a, l ; Remainder - + ret ; a = Modulus - - + + __MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) pop hl ex (sp), hl ; CALLEE - + __MODI8_FAST: ; __FASTCALL__ entry call __DIVI8_FAST ld a, l ; remainder - + ret ; a = Modulus - + #line 3 "printi8.asm" - + __PRINTI8: ; Prints an 8 bits number in Accumulator (A) ; Converts 8 to 32 bits or a jp p, __PRINTU8 - + push af call __PRINT_MINUS pop af neg - + __PRINTU8: PROC - + LOCAL __PRINTU_LOOP - + ld b, 0 ; Counter - + __PRINTU_LOOP: or a jp z, __PRINTU_START - + push bc ld h, 10 call __DIVU8_FAST ; Divides by 10. D'E'H'L' contains modulo (L' since < 10) pop bc - + ld a, l or '0' ; Stores ASCII digit (must be print in reversed order) push af ld a, h inc b jp __PRINTU_LOOP ; Uses JP in loops - + ENDP - + #line 55 "read12.bas" #line 1 "read_restore.asm" - + ;; This implements READ & RESTORE functions ;; Reads a new element from the DATA Address code ;; Updates the DATA_ADDR read ptr for the next read - + ;; Data codification is 1 byte for type followed by data bytes ;; Byte type is encoded as follows - + ;; 00: End of data ;; 01: String ;; 02: Byte @@ -1731,21 +1731,21 @@ __PRINTU_LOOP: ;; 07: ULong ;; 08: Fixed ;; 09: Float - + ;; bit7 is set for a parameter-less function ;; In that case, the next two bytes are the ptr of the function to jump - - - + + + #line 1 "iload32.asm" - + ; __FASTCALL__ routine which ; loads a 32 bits integer into DE,HL ; stored at position pointed by POINTER HL ; DE,HL <-- (HL) - + __ILOAD32: - ld e, (hl) + ld e, (hl) inc hl ld d, (hl) inc hl @@ -1755,28 +1755,28 @@ __ILOAD32: ld l, a ex de, hl ret - + #line 25 "read_restore.asm" #line 1 "iloadf.asm" - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- ((HL)) - + __ILOADF: ld a, (hl) inc hl ld h, (hl) ld l, a - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- (HL) - + __LOADF: ; Loads a 40 bits FP number from address pointed by HL - ld a, (hl) + ld a, (hl) inc hl ld e, (hl) inc hl @@ -1786,57 +1786,57 @@ __LOADF: ; Loads a 40 bits FP number from address pointed by HL inc hl ld b, (hl) ret - + #line 26 "read_restore.asm" #line 1 "ftof16reg.asm" - + #line 1 "ftou32reg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "ftou32reg.asm" - + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) PROC - + LOCAL __IS_FLOAT - + or a - jr nz, __IS_FLOAT + jr nz, __IS_FLOAT ; Here if it is a ZX ROM Integer - + ld h, c ld l, d ld a, e ; Takes sign: FF = -, 0 = + @@ -1844,67 +1844,67 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS inc a jp z, __NEG32 ; Negates if negative ret - + __IS_FLOAT: ; Jumps here if it is a true floating point number - ld h, e + ld h, e push hl ; Stores it for later (Contains Sign in H) - + push de push bc - + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + ;ld a, c ; Get exponent sub 128 ; Exponent -= 128 jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 - + __FTOU32REG_LOOP: exx ; Shift C'B' E'D' << 1, output bit stays in Carry sla d rl e rl b rl c - + exx ; Shift DEHL << 1, inserting the carry on the right rl l rl h rl e rl d - + djnz __FTOU32REG_LOOP - + __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative jp m, __NEG32 ; Negates DEHL - + ret - + ENDP - - + + __FTOU8: ; Converts float in C ED LH to Unsigned byte in A call __FTOU32REG ld a, l ret - + #line 2 "ftof16reg.asm" - + __FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal ; Input FP number in A EDCB (A exponent, EDCB mantissa) - + ld l, a ; Saves exponent for later or d or e @@ -1912,43 +1912,43 @@ __FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal or c ld h, e ret z ; Return if ZERO - + push hl ; Stores it for later (Contains sign in H, exponent in L) - + push de - push bc - + push bc + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + pop bc - + ld a, c ; Get exponent sub 112 ; Exponent -= 128 + 16 - + push bc ; Saves sign in b again - + jp z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jp c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 + 16 (we need to shift 16 bit more) jp __FTOU32REG_LOOP ; proceed as an u32 integer - + #line 27 "read_restore.asm" #line 1 "f16tofreg.asm" - - + + #line 1 "u32tofreg.asm" - - + + __I8TOFREG: ld l, a rlca @@ -1956,35 +1956,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -1992,20 +1992,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -2013,53 +2013,53 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 3 "f16tofreg.asm" - + __F16TOFREG: ; Converts a 16.16 signed fixed point (stored in DEHL) ; to a Floating Point Number returned in (C ED CB) PROC - + LOCAL __F16TOFREG2 - + ld a, d or a ; Test sign - + jp p, __F16TOFREG2 ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __F16TOFREG2 ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - - + + __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in C DE HL - + ld a, d or e or h @@ -2067,29 +2067,29 @@ __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ld b, h ld c, l ret z ; Return 00 0000 0000 if 0 - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 112 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c jp __U32TOFREG_LOOP ; Proceed as an integer - + ENDP - + #line 28 "read_restore.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -2097,25 +2097,25 @@ __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -2124,38 +2124,38 @@ __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -2164,57 +2164,57 @@ __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -2223,47 +2223,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -2273,30 +2273,30 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 29 "read_restore.asm" - - - - - - - - - - - - + + + + + + + + + + + + ;; Updates restore point to the given HL mem. address __RESTORE: PROC LOCAL __DATA_ADDR - + ld (__DATA_ADDR), hl ret - + ;; Reads a value from the DATA mem area and updates __DATA_ADDR ptr to the ;; next item. On Out Of Data, restarts ;; @@ -2308,7 +2308,7 @@ __READ: LOCAL _from_i16, _from_u16 LOCAL _from_i32, _from_u32 LOCAL _from_fixed, __data_error - + push af ; type of data to read ld hl, (__DATA_ADDR) read_restart: @@ -2316,7 +2316,7 @@ read_restart: or a ; 0 => OUT of data jr nz, cont ;; Signals out of data - + ld hl, __DATA__0 ld (__DATA_ADDR), hl jr read_restart ; Start again @@ -2336,7 +2336,7 @@ cont2: ld de, dynamic_cast push de ; ret address jp (hl) ; "call (hl)" - + ;; Now tries to convert the given result to the expected type or raise an error dynamic_cast: exx @@ -2351,13 +2351,13 @@ dynamic_cast: ;; yes, they are ex af, af' ret - + dynamic_cast2: cp 1 ; Requested a number, but read a string? jr nz, dynamic_cast3 call __MEM_FREE ; Frees str from memory jr __data_error - + dynamic_cast3: exx ld b, a ; Read type @@ -2382,7 +2382,7 @@ dynamic_cast3: ld a, c ; Requested type exx ret - + __data_error: ;; When a data is read, but cannot be converted to the requested type ;; that is, the user asked for a string and we read a number or vice versa @@ -2396,7 +2396,7 @@ __data_error: ld b, a ld c, a ret - + _decode_table: dw _from_i8 dw _from_u8 @@ -2405,13 +2405,13 @@ _decode_table: dw _from_i32 dw _from_u32 dw _from_fixed - + _from_i8: cp 4 jr nc, promote_to_i16 ex af, af' ret ;; Was from Byte to Ubyte - + promote_to_i16: ex af, af' ld l, a @@ -2420,14 +2420,14 @@ promote_to_i16: ld h, a ; copy sgn to h ex af, af' jr _before_from_i16 - + _from_u8: ex af, af' ld l, a ld h, 0 ex af, af' ;; Promoted to i16 - + _before_from_i16: _from_i16: cp 6 @@ -2458,7 +2458,7 @@ _from_fixed: ;; From fixed to float _from_u16: ld de, 0 ; HL 0x0000 => 32 bits jp _from_i32 - + dynamic_cast4: ;; The user type is "shorter" than the read one cp 8 ;; required type @@ -2466,7 +2466,7 @@ dynamic_cast4: ex af, af' exx ;; Ok, we must convert from float to f16 jp __FTOF16REG - + before_to_int: ld a, b ;; read type cp 8 ;; @@ -2494,7 +2494,7 @@ coerce_to_int2: ; At this point we have an u/integer in hl ret nc ; Already done. Return the result ld a, l ; Truncate to byte ret - + no_func: exx ld de, dynamic_cast @@ -2513,7 +2513,7 @@ no_func: exx inc hl ret ; jp (sp) => jump to table[a - 1] - + table: LOCAL __01_decode_string LOCAL __02_decode_byte @@ -2524,7 +2524,7 @@ table: LOCAL __07_decode_ulong LOCAL __08_decode_fixed LOCAL __09_decode_float - + ;; 1 -> Decode string ;; 2, 3 -> Decode Byte, UByte ;; 4, 5 -> Decode Integer, UInteger @@ -2540,7 +2540,7 @@ table: dw __07_decode_ulong dw __08_decode_fixed dw __09_decode_float - + __01_decode_string: ld e, (hl) inc hl @@ -2549,14 +2549,14 @@ __01_decode_string: ld (__DATA_ADDR), hl ;; Store address of next DATA ex de, hl jp __LOADSTR - + __02_decode_byte: __03_decode_ubyte: ld a, (hl) inc hl ld (__DATA_ADDR), hl ret - + __04_decode_integer: __05_decode_uinteger: ld e, (hl) @@ -2566,7 +2566,7 @@ __05_decode_uinteger: ld (__DATA_ADDR), hl ex de, hl ret - + __06_decode_long: __07_decode_ulong: __08_decode_fixed: @@ -2578,29 +2578,29 @@ __08_decode_fixed: inc bc ld (__DATA_ADDR), bc jp __ILOAD32 - + __09_decode_float: call __LOADF inc hl ld (__DATA_ADDR), hl ld h, a ; returns A in H; sets A free ret - + __DATA_ADDR: ;; Stores current DATA ptr dw __DATA__0 ENDP - - - - - - - - - - + + + + + + + + + + #line 56 "read12.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/read4.asm b/tests/functional/read4.asm index 739fa8879..d4f6f9e4a 100644 --- a/tests/functional/read4.asm +++ b/tests/functional/read4.asm @@ -105,12 +105,12 @@ __LABEL0: DEFB 6Ch DEFB 6Fh #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -118,25 +118,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -145,51 +145,51 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -197,12 +197,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -210,7 +210,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -218,10 +218,10 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -229,25 +229,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -256,39 +256,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -296,57 +296,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -358,27 +358,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -390,7 +390,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -398,15 +398,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -431,14 +431,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -446,25 +446,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -473,30 +473,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -504,40 +504,40 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 93 "read4.bas" #line 1 "mulf.asm" - + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -553,7 +553,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 2 "mulf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) ; All of them uses A EDCB registers as 1st paramter. @@ -562,25 +562,25 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; ; Uses CALLEE convention ; ------------------------------------------------------------- - + __MULF: ; Multiplication call __FPSTACK_PUSH2 - + ; ------------- ROM MUL rst 28h - defb 04h ; + defb 04h ; defb 38h; ; END CALC - + jp __FPSTACK_POP - + #line 94 "read4.bas" #line 1 "pow.asm" - - - + + + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) - + ; All of them uses A EDCB registers as 1st paramter. ; For binary operators, the 2n operator must be pushed into the ; stack, in the order A DE BC. @@ -591,31 +591,31 @@ __MULF: ; Multiplication ; 1 st parameter is the BASE (A ED CB) ; 2 nd parameter (Top of the stack) is Exponent ; ------------------------------------------------------------- - + __POW: ; Exponentiation PROC - + call __FPSTACK_PUSH2 - + ; ------------- ROM POW rst 28h defb 01h ; Exchange => 1, Base defb 06h ; POW defb 38h; ; END CALC - + jp __FPSTACK_POP - + ENDP - + #line 95 "read4.bas" #line 1 "pushf.asm" - - - ; Routine to push Float pointed by HL + + + ; Routine to push Float pointed by HL ; Into the stack. Notice that the hl points to the last ; byte of the FP number. ; Uses H'L' B'C' and D'E' to preserve ABCDEHL registers - + __FP_PUSH_REV: push hl exx @@ -636,18 +636,18 @@ __FP_PUSH_REV: push bc ; Return Address exx ret - - + + #line 96 "read4.bas" #line 1 "read_restore.asm" - + ;; This implements READ & RESTORE functions ;; Reads a new element from the DATA Address code ;; Updates the DATA_ADDR read ptr for the next read - + ;; Data codification is 1 byte for type followed by data bytes ;; Byte type is encoded as follows - + ;; 00: End of data ;; 01: String ;; 02: Byte @@ -658,21 +658,21 @@ __FP_PUSH_REV: ;; 07: ULong ;; 08: Fixed ;; 09: Float - + ;; bit7 is set for a parameter-less function ;; In that case, the next two bytes are the ptr of the function to jump - - - + + + #line 1 "iload32.asm" - + ; __FASTCALL__ routine which ; loads a 32 bits integer into DE,HL ; stored at position pointed by POINTER HL ; DE,HL <-- (HL) - + __ILOAD32: - ld e, (hl) + ld e, (hl) inc hl ld d, (hl) inc hl @@ -682,28 +682,28 @@ __ILOAD32: ld l, a ex de, hl ret - + #line 25 "read_restore.asm" #line 1 "iloadf.asm" - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- ((HL)) - + __ILOADF: ld a, (hl) inc hl ld h, (hl) ld l, a - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- (HL) - + __LOADF: ; Loads a 40 bits FP number from address pointed by HL - ld a, (hl) + ld a, (hl) inc hl ld e, (hl) inc hl @@ -713,57 +713,57 @@ __LOADF: ; Loads a 40 bits FP number from address pointed by HL inc hl ld b, (hl) ret - + #line 26 "read_restore.asm" #line 1 "ftof16reg.asm" - + #line 1 "ftou32reg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "ftou32reg.asm" - + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) PROC - + LOCAL __IS_FLOAT - + or a - jr nz, __IS_FLOAT + jr nz, __IS_FLOAT ; Here if it is a ZX ROM Integer - + ld h, c ld l, d ld a, e ; Takes sign: FF = -, 0 = + @@ -771,67 +771,67 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS inc a jp z, __NEG32 ; Negates if negative ret - + __IS_FLOAT: ; Jumps here if it is a true floating point number - ld h, e + ld h, e push hl ; Stores it for later (Contains Sign in H) - + push de push bc - + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + ;ld a, c ; Get exponent sub 128 ; Exponent -= 128 jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 - + __FTOU32REG_LOOP: exx ; Shift C'B' E'D' << 1, output bit stays in Carry sla d rl e rl b rl c - + exx ; Shift DEHL << 1, inserting the carry on the right rl l rl h rl e rl d - + djnz __FTOU32REG_LOOP - + __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative jp m, __NEG32 ; Negates DEHL - + ret - + ENDP - - + + __FTOU8: ; Converts float in C ED LH to Unsigned byte in A call __FTOU32REG ld a, l ret - + #line 2 "ftof16reg.asm" - + __FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal ; Input FP number in A EDCB (A exponent, EDCB mantissa) - + ld l, a ; Saves exponent for later or d or e @@ -839,43 +839,43 @@ __FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal or c ld h, e ret z ; Return if ZERO - + push hl ; Stores it for later (Contains sign in H, exponent in L) - + push de - push bc - + push bc + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + pop bc - + ld a, c ; Get exponent sub 112 ; Exponent -= 128 + 16 - + push bc ; Saves sign in b again - + jp z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jp c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 + 16 (we need to shift 16 bit more) jp __FTOU32REG_LOOP ; proceed as an u32 integer - + #line 27 "read_restore.asm" #line 1 "f16tofreg.asm" - - + + #line 1 "u32tofreg.asm" - - + + __I8TOFREG: ld l, a rlca @@ -883,35 +883,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -919,20 +919,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -940,53 +940,53 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 3 "f16tofreg.asm" - + __F16TOFREG: ; Converts a 16.16 signed fixed point (stored in DEHL) ; to a Floating Point Number returned in (C ED CB) PROC - + LOCAL __F16TOFREG2 - + ld a, d or a ; Test sign - + jp p, __F16TOFREG2 ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __F16TOFREG2 ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - - + + __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in C DE HL - + ld a, d or e or h @@ -994,29 +994,29 @@ __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ld b, h ld c, l ret z ; Return 00 0000 0000 if 0 - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 112 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c jp __U32TOFREG_LOOP ; Proceed as an integer - + ENDP - + #line 28 "read_restore.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1024,25 +1024,25 @@ __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1051,38 +1051,38 @@ __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -1091,57 +1091,57 @@ __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -1150,47 +1150,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -1200,30 +1200,30 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 29 "read_restore.asm" - - - - - - - - - - - - + + + + + + + + + + + + ;; Updates restore point to the given HL mem. address __RESTORE: PROC LOCAL __DATA_ADDR - + ld (__DATA_ADDR), hl ret - + ;; Reads a value from the DATA mem area and updates __DATA_ADDR ptr to the ;; next item. On Out Of Data, restarts ;; @@ -1235,7 +1235,7 @@ __READ: LOCAL _from_i16, _from_u16 LOCAL _from_i32, _from_u32 LOCAL _from_fixed, __data_error - + push af ; type of data to read ld hl, (__DATA_ADDR) read_restart: @@ -1243,7 +1243,7 @@ read_restart: or a ; 0 => OUT of data jr nz, cont ;; Signals out of data - + ld hl, __DATA__0 ld (__DATA_ADDR), hl jr read_restart ; Start again @@ -1263,7 +1263,7 @@ cont2: ld de, dynamic_cast push de ; ret address jp (hl) ; "call (hl)" - + ;; Now tries to convert the given result to the expected type or raise an error dynamic_cast: exx @@ -1278,13 +1278,13 @@ dynamic_cast: ;; yes, they are ex af, af' ret - + dynamic_cast2: cp 1 ; Requested a number, but read a string? jr nz, dynamic_cast3 call __MEM_FREE ; Frees str from memory jr __data_error - + dynamic_cast3: exx ld b, a ; Read type @@ -1309,7 +1309,7 @@ dynamic_cast3: ld a, c ; Requested type exx ret - + __data_error: ;; When a data is read, but cannot be converted to the requested type ;; that is, the user asked for a string and we read a number or vice versa @@ -1323,7 +1323,7 @@ __data_error: ld b, a ld c, a ret - + _decode_table: dw _from_i8 dw _from_u8 @@ -1332,13 +1332,13 @@ _decode_table: dw _from_i32 dw _from_u32 dw _from_fixed - + _from_i8: cp 4 jr nc, promote_to_i16 ex af, af' ret ;; Was from Byte to Ubyte - + promote_to_i16: ex af, af' ld l, a @@ -1347,14 +1347,14 @@ promote_to_i16: ld h, a ; copy sgn to h ex af, af' jr _before_from_i16 - + _from_u8: ex af, af' ld l, a ld h, 0 ex af, af' ;; Promoted to i16 - + _before_from_i16: _from_i16: cp 6 @@ -1385,7 +1385,7 @@ _from_fixed: ;; From fixed to float _from_u16: ld de, 0 ; HL 0x0000 => 32 bits jp _from_i32 - + dynamic_cast4: ;; The user type is "shorter" than the read one cp 8 ;; required type @@ -1393,7 +1393,7 @@ dynamic_cast4: ex af, af' exx ;; Ok, we must convert from float to f16 jp __FTOF16REG - + before_to_int: ld a, b ;; read type cp 8 ;; @@ -1421,7 +1421,7 @@ coerce_to_int2: ; At this point we have an u/integer in hl ret nc ; Already done. Return the result ld a, l ; Truncate to byte ret - + no_func: exx ld de, dynamic_cast @@ -1440,7 +1440,7 @@ no_func: exx inc hl ret ; jp (sp) => jump to table[a - 1] - + table: LOCAL __01_decode_string LOCAL __02_decode_byte @@ -1451,7 +1451,7 @@ table: LOCAL __07_decode_ulong LOCAL __08_decode_fixed LOCAL __09_decode_float - + ;; 1 -> Decode string ;; 2, 3 -> Decode Byte, UByte ;; 4, 5 -> Decode Integer, UInteger @@ -1467,7 +1467,7 @@ table: dw __07_decode_ulong dw __08_decode_fixed dw __09_decode_float - + __01_decode_string: ld e, (hl) inc hl @@ -1476,14 +1476,14 @@ __01_decode_string: ld (__DATA_ADDR), hl ;; Store address of next DATA ex de, hl jp __LOADSTR - + __02_decode_byte: __03_decode_ubyte: ld a, (hl) inc hl ld (__DATA_ADDR), hl ret - + __04_decode_integer: __05_decode_uinteger: ld e, (hl) @@ -1493,7 +1493,7 @@ __05_decode_uinteger: ld (__DATA_ADDR), hl ex de, hl ret - + __06_decode_long: __07_decode_ulong: __08_decode_fixed: @@ -1505,44 +1505,44 @@ __08_decode_fixed: inc bc ld (__DATA_ADDR), bc jp __ILOAD32 - + __09_decode_float: call __LOADF inc hl ld (__DATA_ADDR), hl ld h, a ; returns A in H; sets A free ret - + __DATA_ADDR: ;; Stores current DATA ptr dw __DATA__0 ENDP - - - - - - - - - - + + + + + + + + + + #line 97 "read4.bas" #line 1 "sin.asm" - - - + + + SIN: ; Computes SIN using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 1Fh defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 98 "read4.bas" #line 1 "storef.asm" - + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -1550,7 +1550,7 @@ __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory pop hl ; HL <- IX add hl, de ; HL <- IX + HL pop de - + __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register ex af, af' ld a, (hl) @@ -1558,7 +1558,7 @@ __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address ld h, (hl) ld l, a ; HL = (HL) ex af, af' - + __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), a inc hl @@ -1570,23 +1570,23 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL inc hl ld (hl), b ret - + #line 99 "read4.bas" #line 1 "tan.asm" - - - + + + TAN: ; Computes TAN using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 21h ; TAN defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 100 "read4.bas" - + ZXBASIC_USER_DATA: _v: DEFB 81h diff --git a/tests/functional/read5.asm b/tests/functional/read5.asm index 1b18c152f..875272c60 100644 --- a/tests/functional/read5.asm +++ b/tests/functional/read5.asm @@ -127,40 +127,40 @@ __DATA__0: __DATA__END: DEFB 00h #line 1 "mulf.asm" - + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -176,7 +176,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 2 "mulf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) ; All of them uses A EDCB registers as 1st paramter. @@ -185,25 +185,25 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; ; Uses CALLEE convention ; ------------------------------------------------------------- - + __MULF: ; Multiplication call __FPSTACK_PUSH2 - + ; ------------- ROM MUL rst 28h - defb 04h ; + defb 04h ; defb 38h; ; END CALC - + jp __FPSTACK_POP - + #line 114 "read5.bas" #line 1 "pow.asm" - - - + + + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) - + ; All of them uses A EDCB registers as 1st paramter. ; For binary operators, the 2n operator must be pushed into the ; stack, in the order A DE BC. @@ -214,35 +214,35 @@ __MULF: ; Multiplication ; 1 st parameter is the BASE (A ED CB) ; 2 nd parameter (Top of the stack) is Exponent ; ------------------------------------------------------------- - + __POW: ; Exponentiation PROC - + call __FPSTACK_PUSH2 - + ; ------------- ROM POW rst 28h defb 01h ; Exchange => 1, Base defb 06h ; POW defb 38h; ; END CALC - + jp __FPSTACK_POP - + ENDP - + #line 115 "read5.bas" #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -250,46 +250,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -302,43 +302,43 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -346,12 +346,12 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -359,51 +359,51 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "in_screen.asm" - + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -412,17 +412,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -430,26 +430,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -463,45 +463,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -512,28 +512,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -541,28 +541,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -571,83 +571,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -656,32 +656,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -691,7 +691,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -699,20 +699,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -722,7 +722,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -733,19 +733,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -755,7 +755,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -766,19 +766,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -788,7 +788,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -801,22 +801,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -825,79 +825,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -906,75 +906,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -984,7 +984,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -996,16 +996,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1019,49 +1019,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1072,17 +1072,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1095,27 +1095,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1123,10 +1123,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1143,80 +1143,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1233,8 +1233,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1258,17 +1258,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1279,7 +1279,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1289,21 +1289,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1322,9 +1322,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1349,23 +1349,23 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 116 "read5.bas" #line 1 "printf.asm" - + #line 1 "printstr.asm" - - - - + + + + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1373,25 +1373,25 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1400,41 +1400,41 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1442,25 +1442,25 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1469,39 +1469,39 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -1509,56 +1509,56 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -1567,57 +1567,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -1626,47 +1626,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -1676,51 +1676,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 5 "printstr.asm" - + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1729,62 +1729,62 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 2 "printf.asm" - - - + + + __PRINTF: ; Prints a Fixed point Number stored in C ED LH PROC - + LOCAL RECLAIM2 LOCAL STK_END STK_END EQU 5C65h - + ld hl, (ATTR_T) push hl ; Saves ATTR_T since BUG ROM changes it - + ld hl, (STK_END) push hl ; Stores STK_END - + call __FPSTACK_PUSH ; Push number into stack rst 28h ; # Rom Calculator defb 2Eh ; # STR$(x) defb 38h ; # END CALC call __FPSTACK_POP ; Recovers string parameters to A ED CB - + pop hl ld (STK_END), hl ; Balance STK_END to avoid STR$ bug - + pop hl ld (ATTR_T), hl ; Restores ATTR_T - + ex de, hl ; String position now in HL - + push bc xor a ; Avoid the str to be FREED from heap call __PRINT_STR - pop bc + pop bc inc bc - + jp RECLAIM2 ; Frees TMP Memory - + RECLAIM2 EQU 19E8h - + ENDP - + #line 117 "read5.bas" #line 1 "read_restore.asm" - + ;; This implements READ & RESTORE functions ;; Reads a new element from the DATA Address code ;; Updates the DATA_ADDR read ptr for the next read - + ;; Data codification is 1 byte for type followed by data bytes ;; Byte type is encoded as follows - + ;; 00: End of data ;; 01: String ;; 02: Byte @@ -1795,18 +1795,18 @@ __PRINTF: ; Prints a Fixed point Number stored in C ED LH ;; 07: ULong ;; 08: Fixed ;; 09: Float - + ;; bit7 is set for a parameter-less function ;; In that case, the next two bytes are the ptr of the function to jump - - + + #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1814,25 +1814,25 @@ __PRINTF: ; Prints a Fixed point Number stored in C ED LH ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1841,40 +1841,40 @@ __PRINTF: ; Prints a Fixed point Number stored in C ED LH ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - - + + + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -1886,27 +1886,27 @@ __PRINTF: ; Prints a Fixed point Number stored in C ED LH ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -1918,7 +1918,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -1926,15 +1926,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -1959,14 +1959,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -1974,25 +1974,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -2001,30 +2001,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -2032,14 +2032,14 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 24 "read_restore.asm" #line 1 "iload32.asm" - + ; __FASTCALL__ routine which ; loads a 32 bits integer into DE,HL ; stored at position pointed by POINTER HL ; DE,HL <-- (HL) - + __ILOAD32: - ld e, (hl) + ld e, (hl) inc hl ld d, (hl) inc hl @@ -2049,28 +2049,28 @@ __ILOAD32: ld l, a ex de, hl ret - + #line 25 "read_restore.asm" #line 1 "iloadf.asm" - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- ((HL)) - + __ILOADF: ld a, (hl) inc hl ld h, (hl) ld l, a - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- (HL) - + __LOADF: ; Loads a 40 bits FP number from address pointed by HL - ld a, (hl) + ld a, (hl) inc hl ld e, (hl) inc hl @@ -2080,57 +2080,57 @@ __LOADF: ; Loads a 40 bits FP number from address pointed by HL inc hl ld b, (hl) ret - + #line 26 "read_restore.asm" #line 1 "ftof16reg.asm" - + #line 1 "ftou32reg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "ftou32reg.asm" - + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) PROC - + LOCAL __IS_FLOAT - + or a - jr nz, __IS_FLOAT + jr nz, __IS_FLOAT ; Here if it is a ZX ROM Integer - + ld h, c ld l, d ld a, e ; Takes sign: FF = -, 0 = + @@ -2138,67 +2138,67 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS inc a jp z, __NEG32 ; Negates if negative ret - + __IS_FLOAT: ; Jumps here if it is a true floating point number - ld h, e + ld h, e push hl ; Stores it for later (Contains Sign in H) - + push de push bc - + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + ;ld a, c ; Get exponent sub 128 ; Exponent -= 128 jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 - + __FTOU32REG_LOOP: exx ; Shift C'B' E'D' << 1, output bit stays in Carry sla d rl e rl b rl c - + exx ; Shift DEHL << 1, inserting the carry on the right rl l rl h rl e rl d - + djnz __FTOU32REG_LOOP - + __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative jp m, __NEG32 ; Negates DEHL - + ret - + ENDP - - + + __FTOU8: ; Converts float in C ED LH to Unsigned byte in A call __FTOU32REG ld a, l ret - + #line 2 "ftof16reg.asm" - + __FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal ; Input FP number in A EDCB (A exponent, EDCB mantissa) - + ld l, a ; Saves exponent for later or d or e @@ -2206,43 +2206,43 @@ __FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal or c ld h, e ret z ; Return if ZERO - + push hl ; Stores it for later (Contains sign in H, exponent in L) - + push de - push bc - + push bc + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + pop bc - + ld a, c ; Get exponent sub 112 ; Exponent -= 128 + 16 - + push bc ; Saves sign in b again - + jp z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jp c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 + 16 (we need to shift 16 bit more) jp __FTOU32REG_LOOP ; proceed as an u32 integer - + #line 27 "read_restore.asm" #line 1 "f16tofreg.asm" - - + + #line 1 "u32tofreg.asm" - - + + __I8TOFREG: ld l, a rlca @@ -2250,35 +2250,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -2286,20 +2286,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -2307,53 +2307,53 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 3 "f16tofreg.asm" - + __F16TOFREG: ; Converts a 16.16 signed fixed point (stored in DEHL) ; to a Floating Point Number returned in (C ED CB) PROC - + LOCAL __F16TOFREG2 - + ld a, d or a ; Test sign - + jp p, __F16TOFREG2 ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __F16TOFREG2 ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - - + + __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in C DE HL - + ld a, d or e or h @@ -2361,45 +2361,45 @@ __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ld b, h ld c, l ret z ; Return 00 0000 0000 if 0 - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 112 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c jp __U32TOFREG_LOOP ; Proceed as an integer - + ENDP - + #line 28 "read_restore.asm" - - - - - - - - - - - - - + + + + + + + + + + + + + ;; Updates restore point to the given HL mem. address __RESTORE: PROC LOCAL __DATA_ADDR - + ld (__DATA_ADDR), hl ret - + ;; Reads a value from the DATA mem area and updates __DATA_ADDR ptr to the ;; next item. On Out Of Data, restarts ;; @@ -2411,7 +2411,7 @@ __READ: LOCAL _from_i16, _from_u16 LOCAL _from_i32, _from_u32 LOCAL _from_fixed, __data_error - + push af ; type of data to read ld hl, (__DATA_ADDR) read_restart: @@ -2419,7 +2419,7 @@ read_restart: or a ; 0 => OUT of data jr nz, cont ;; Signals out of data - + ld hl, __DATA__0 ld (__DATA_ADDR), hl jr read_restart ; Start again @@ -2439,7 +2439,7 @@ cont2: ld de, dynamic_cast push de ; ret address jp (hl) ; "call (hl)" - + ;; Now tries to convert the given result to the expected type or raise an error dynamic_cast: exx @@ -2454,13 +2454,13 @@ dynamic_cast: ;; yes, they are ex af, af' ret - + dynamic_cast2: cp 1 ; Requested a number, but read a string? jr nz, dynamic_cast3 call __MEM_FREE ; Frees str from memory jr __data_error - + dynamic_cast3: exx ld b, a ; Read type @@ -2485,7 +2485,7 @@ dynamic_cast3: ld a, c ; Requested type exx ret - + __data_error: ;; When a data is read, but cannot be converted to the requested type ;; that is, the user asked for a string and we read a number or vice versa @@ -2499,7 +2499,7 @@ __data_error: ld b, a ld c, a ret - + _decode_table: dw _from_i8 dw _from_u8 @@ -2508,13 +2508,13 @@ _decode_table: dw _from_i32 dw _from_u32 dw _from_fixed - + _from_i8: cp 4 jr nc, promote_to_i16 ex af, af' ret ;; Was from Byte to Ubyte - + promote_to_i16: ex af, af' ld l, a @@ -2523,14 +2523,14 @@ promote_to_i16: ld h, a ; copy sgn to h ex af, af' jr _before_from_i16 - + _from_u8: ex af, af' ld l, a ld h, 0 ex af, af' ;; Promoted to i16 - + _before_from_i16: _from_i16: cp 6 @@ -2561,7 +2561,7 @@ _from_fixed: ;; From fixed to float _from_u16: ld de, 0 ; HL 0x0000 => 32 bits jp _from_i32 - + dynamic_cast4: ;; The user type is "shorter" than the read one cp 8 ;; required type @@ -2569,7 +2569,7 @@ dynamic_cast4: ex af, af' exx ;; Ok, we must convert from float to f16 jp __FTOF16REG - + before_to_int: ld a, b ;; read type cp 8 ;; @@ -2597,7 +2597,7 @@ coerce_to_int2: ; At this point we have an u/integer in hl ret nc ; Already done. Return the result ld a, l ; Truncate to byte ret - + no_func: exx ld de, dynamic_cast @@ -2616,7 +2616,7 @@ no_func: exx inc hl ret ; jp (sp) => jump to table[a - 1] - + table: LOCAL __01_decode_string LOCAL __02_decode_byte @@ -2627,7 +2627,7 @@ table: LOCAL __07_decode_ulong LOCAL __08_decode_fixed LOCAL __09_decode_float - + ;; 1 -> Decode string ;; 2, 3 -> Decode Byte, UByte ;; 4, 5 -> Decode Integer, UInteger @@ -2643,7 +2643,7 @@ table: dw __07_decode_ulong dw __08_decode_fixed dw __09_decode_float - + __01_decode_string: ld e, (hl) inc hl @@ -2652,14 +2652,14 @@ __01_decode_string: ld (__DATA_ADDR), hl ;; Store address of next DATA ex de, hl jp __LOADSTR - + __02_decode_byte: __03_decode_ubyte: ld a, (hl) inc hl ld (__DATA_ADDR), hl ret - + __04_decode_integer: __05_decode_uinteger: ld e, (hl) @@ -2669,7 +2669,7 @@ __05_decode_uinteger: ld (__DATA_ADDR), hl ex de, hl ret - + __06_decode_long: __07_decode_ulong: __08_decode_fixed: @@ -2681,44 +2681,44 @@ __08_decode_fixed: inc bc ld (__DATA_ADDR), bc jp __ILOAD32 - + __09_decode_float: call __LOADF inc hl ld (__DATA_ADDR), hl ld h, a ; returns A in H; sets A free ret - + __DATA_ADDR: ;; Stores current DATA ptr dw __DATA__0 ENDP - - - - - - - - - - + + + + + + + + + + #line 118 "read5.bas" #line 1 "sin.asm" - - - + + + SIN: ; Computes SIN using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 1Fh defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 119 "read5.bas" #line 1 "storef.asm" - + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -2726,7 +2726,7 @@ __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory pop hl ; HL <- IX add hl, de ; HL <- IX + HL pop de - + __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register ex af, af' ld a, (hl) @@ -2734,7 +2734,7 @@ __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address ld h, (hl) ld l, a ; HL = (HL) ex af, af' - + __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), a inc hl @@ -2746,23 +2746,23 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL inc hl ld (hl), b ret - + #line 120 "read5.bas" #line 1 "tan.asm" - - - + + + TAN: ; Computes TAN using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 21h ; TAN defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 121 "read5.bas" - + ZXBASIC_USER_DATA: _v: DEFB 81h diff --git a/tests/functional/read8.asm b/tests/functional/read8.asm index 0708f8db6..94be629c2 100644 --- a/tests/functional/read8.asm +++ b/tests/functional/read8.asm @@ -118,40 +118,40 @@ __DATA__0: __DATA__END: DEFB 00h #line 1 "mulf.asm" - + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -167,7 +167,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 2 "mulf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) ; All of them uses A EDCB registers as 1st paramter. @@ -176,25 +176,25 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; ; Uses CALLEE convention ; ------------------------------------------------------------- - + __MULF: ; Multiplication call __FPSTACK_PUSH2 - + ; ------------- ROM MUL rst 28h - defb 04h ; + defb 04h ; defb 38h; ; END CALC - + jp __FPSTACK_POP - + #line 105 "read8.bas" #line 1 "pow.asm" - - - + + + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) - + ; All of them uses A EDCB registers as 1st paramter. ; For binary operators, the 2n operator must be pushed into the ; stack, in the order A DE BC. @@ -205,35 +205,35 @@ __MULF: ; Multiplication ; 1 st parameter is the BASE (A ED CB) ; 2 nd parameter (Top of the stack) is Exponent ; ------------------------------------------------------------- - + __POW: ; Exponentiation PROC - + call __FPSTACK_PUSH2 - + ; ------------- ROM POW rst 28h defb 01h ; Exchange => 1, Base defb 06h ; POW defb 38h; ; END CALC - + jp __FPSTACK_POP - + ENDP - + #line 106 "read8.bas" #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -241,46 +241,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -293,43 +293,43 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -337,12 +337,12 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -350,51 +350,51 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "in_screen.asm" - + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -403,17 +403,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -421,26 +421,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -454,45 +454,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -503,28 +503,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -532,28 +532,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -562,83 +562,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -647,32 +647,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -682,7 +682,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -690,20 +690,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -713,7 +713,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -724,19 +724,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -746,7 +746,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -757,19 +757,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -779,7 +779,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -792,22 +792,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -816,79 +816,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -897,75 +897,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -975,7 +975,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -987,16 +987,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1010,49 +1010,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1063,17 +1063,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1086,27 +1086,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1114,10 +1114,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1134,80 +1134,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1224,8 +1224,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1249,17 +1249,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1270,7 +1270,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1280,21 +1280,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1313,9 +1313,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1340,23 +1340,23 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 107 "read8.bas" #line 1 "printf.asm" - + #line 1 "printstr.asm" - - - - + + + + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1364,25 +1364,25 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1391,41 +1391,41 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1433,25 +1433,25 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1460,39 +1460,39 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -1500,56 +1500,56 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -1558,57 +1558,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -1617,47 +1617,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -1667,51 +1667,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 5 "printstr.asm" - + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1720,62 +1720,62 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 2 "printf.asm" - - - + + + __PRINTF: ; Prints a Fixed point Number stored in C ED LH PROC - + LOCAL RECLAIM2 LOCAL STK_END STK_END EQU 5C65h - + ld hl, (ATTR_T) push hl ; Saves ATTR_T since BUG ROM changes it - + ld hl, (STK_END) push hl ; Stores STK_END - + call __FPSTACK_PUSH ; Push number into stack rst 28h ; # Rom Calculator defb 2Eh ; # STR$(x) defb 38h ; # END CALC call __FPSTACK_POP ; Recovers string parameters to A ED CB - + pop hl ld (STK_END), hl ; Balance STK_END to avoid STR$ bug - + pop hl ld (ATTR_T), hl ; Restores ATTR_T - + ex de, hl ; String position now in HL - + push bc xor a ; Avoid the str to be FREED from heap call __PRINT_STR - pop bc + pop bc inc bc - + jp RECLAIM2 ; Frees TMP Memory - + RECLAIM2 EQU 19E8h - + ENDP - + #line 108 "read8.bas" #line 1 "read_restore.asm" - + ;; This implements READ & RESTORE functions ;; Reads a new element from the DATA Address code ;; Updates the DATA_ADDR read ptr for the next read - + ;; Data codification is 1 byte for type followed by data bytes ;; Byte type is encoded as follows - + ;; 00: End of data ;; 01: String ;; 02: Byte @@ -1786,18 +1786,18 @@ __PRINTF: ; Prints a Fixed point Number stored in C ED LH ;; 07: ULong ;; 08: Fixed ;; 09: Float - + ;; bit7 is set for a parameter-less function ;; In that case, the next two bytes are the ptr of the function to jump - - + + #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1805,25 +1805,25 @@ __PRINTF: ; Prints a Fixed point Number stored in C ED LH ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1832,40 +1832,40 @@ __PRINTF: ; Prints a Fixed point Number stored in C ED LH ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - - + + + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -1877,27 +1877,27 @@ __PRINTF: ; Prints a Fixed point Number stored in C ED LH ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -1909,7 +1909,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -1917,15 +1917,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -1950,14 +1950,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -1965,25 +1965,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -1992,30 +1992,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -2023,14 +2023,14 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 24 "read_restore.asm" #line 1 "iload32.asm" - + ; __FASTCALL__ routine which ; loads a 32 bits integer into DE,HL ; stored at position pointed by POINTER HL ; DE,HL <-- (HL) - + __ILOAD32: - ld e, (hl) + ld e, (hl) inc hl ld d, (hl) inc hl @@ -2040,28 +2040,28 @@ __ILOAD32: ld l, a ex de, hl ret - + #line 25 "read_restore.asm" #line 1 "iloadf.asm" - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- ((HL)) - + __ILOADF: ld a, (hl) inc hl ld h, (hl) ld l, a - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- (HL) - + __LOADF: ; Loads a 40 bits FP number from address pointed by HL - ld a, (hl) + ld a, (hl) inc hl ld e, (hl) inc hl @@ -2071,57 +2071,57 @@ __LOADF: ; Loads a 40 bits FP number from address pointed by HL inc hl ld b, (hl) ret - + #line 26 "read_restore.asm" #line 1 "ftof16reg.asm" - + #line 1 "ftou32reg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "ftou32reg.asm" - + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) PROC - + LOCAL __IS_FLOAT - + or a - jr nz, __IS_FLOAT + jr nz, __IS_FLOAT ; Here if it is a ZX ROM Integer - + ld h, c ld l, d ld a, e ; Takes sign: FF = -, 0 = + @@ -2129,67 +2129,67 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS inc a jp z, __NEG32 ; Negates if negative ret - + __IS_FLOAT: ; Jumps here if it is a true floating point number - ld h, e + ld h, e push hl ; Stores it for later (Contains Sign in H) - + push de push bc - + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + ;ld a, c ; Get exponent sub 128 ; Exponent -= 128 jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 - + __FTOU32REG_LOOP: exx ; Shift C'B' E'D' << 1, output bit stays in Carry sla d rl e rl b rl c - + exx ; Shift DEHL << 1, inserting the carry on the right rl l rl h rl e rl d - + djnz __FTOU32REG_LOOP - + __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative jp m, __NEG32 ; Negates DEHL - + ret - + ENDP - - + + __FTOU8: ; Converts float in C ED LH to Unsigned byte in A call __FTOU32REG ld a, l ret - + #line 2 "ftof16reg.asm" - + __FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal ; Input FP number in A EDCB (A exponent, EDCB mantissa) - + ld l, a ; Saves exponent for later or d or e @@ -2197,43 +2197,43 @@ __FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal or c ld h, e ret z ; Return if ZERO - + push hl ; Stores it for later (Contains sign in H, exponent in L) - + push de - push bc - + push bc + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + pop bc - + ld a, c ; Get exponent sub 112 ; Exponent -= 128 + 16 - + push bc ; Saves sign in b again - + jp z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jp c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 + 16 (we need to shift 16 bit more) jp __FTOU32REG_LOOP ; proceed as an u32 integer - + #line 27 "read_restore.asm" #line 1 "f16tofreg.asm" - - + + #line 1 "u32tofreg.asm" - - + + __I8TOFREG: ld l, a rlca @@ -2241,35 +2241,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -2277,20 +2277,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -2298,53 +2298,53 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 3 "f16tofreg.asm" - + __F16TOFREG: ; Converts a 16.16 signed fixed point (stored in DEHL) ; to a Floating Point Number returned in (C ED CB) PROC - + LOCAL __F16TOFREG2 - + ld a, d or a ; Test sign - + jp p, __F16TOFREG2 ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __F16TOFREG2 ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - - + + __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in C DE HL - + ld a, d or e or h @@ -2352,45 +2352,45 @@ __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ld b, h ld c, l ret z ; Return 00 0000 0000 if 0 - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 112 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c jp __U32TOFREG_LOOP ; Proceed as an integer - + ENDP - + #line 28 "read_restore.asm" - - - - - - - - - - - - - + + + + + + + + + + + + + ;; Updates restore point to the given HL mem. address __RESTORE: PROC LOCAL __DATA_ADDR - + ld (__DATA_ADDR), hl ret - + ;; Reads a value from the DATA mem area and updates __DATA_ADDR ptr to the ;; next item. On Out Of Data, restarts ;; @@ -2402,7 +2402,7 @@ __READ: LOCAL _from_i16, _from_u16 LOCAL _from_i32, _from_u32 LOCAL _from_fixed, __data_error - + push af ; type of data to read ld hl, (__DATA_ADDR) read_restart: @@ -2410,7 +2410,7 @@ read_restart: or a ; 0 => OUT of data jr nz, cont ;; Signals out of data - + ld hl, __DATA__0 ld (__DATA_ADDR), hl jr read_restart ; Start again @@ -2430,7 +2430,7 @@ cont2: ld de, dynamic_cast push de ; ret address jp (hl) ; "call (hl)" - + ;; Now tries to convert the given result to the expected type or raise an error dynamic_cast: exx @@ -2445,13 +2445,13 @@ dynamic_cast: ;; yes, they are ex af, af' ret - + dynamic_cast2: cp 1 ; Requested a number, but read a string? jr nz, dynamic_cast3 call __MEM_FREE ; Frees str from memory jr __data_error - + dynamic_cast3: exx ld b, a ; Read type @@ -2476,7 +2476,7 @@ dynamic_cast3: ld a, c ; Requested type exx ret - + __data_error: ;; When a data is read, but cannot be converted to the requested type ;; that is, the user asked for a string and we read a number or vice versa @@ -2490,7 +2490,7 @@ __data_error: ld b, a ld c, a ret - + _decode_table: dw _from_i8 dw _from_u8 @@ -2499,13 +2499,13 @@ _decode_table: dw _from_i32 dw _from_u32 dw _from_fixed - + _from_i8: cp 4 jr nc, promote_to_i16 ex af, af' ret ;; Was from Byte to Ubyte - + promote_to_i16: ex af, af' ld l, a @@ -2514,14 +2514,14 @@ promote_to_i16: ld h, a ; copy sgn to h ex af, af' jr _before_from_i16 - + _from_u8: ex af, af' ld l, a ld h, 0 ex af, af' ;; Promoted to i16 - + _before_from_i16: _from_i16: cp 6 @@ -2552,7 +2552,7 @@ _from_fixed: ;; From fixed to float _from_u16: ld de, 0 ; HL 0x0000 => 32 bits jp _from_i32 - + dynamic_cast4: ;; The user type is "shorter" than the read one cp 8 ;; required type @@ -2560,7 +2560,7 @@ dynamic_cast4: ex af, af' exx ;; Ok, we must convert from float to f16 jp __FTOF16REG - + before_to_int: ld a, b ;; read type cp 8 ;; @@ -2588,7 +2588,7 @@ coerce_to_int2: ; At this point we have an u/integer in hl ret nc ; Already done. Return the result ld a, l ; Truncate to byte ret - + no_func: exx ld de, dynamic_cast @@ -2607,7 +2607,7 @@ no_func: exx inc hl ret ; jp (sp) => jump to table[a - 1] - + table: LOCAL __01_decode_string LOCAL __02_decode_byte @@ -2618,7 +2618,7 @@ table: LOCAL __07_decode_ulong LOCAL __08_decode_fixed LOCAL __09_decode_float - + ;; 1 -> Decode string ;; 2, 3 -> Decode Byte, UByte ;; 4, 5 -> Decode Integer, UInteger @@ -2634,7 +2634,7 @@ table: dw __07_decode_ulong dw __08_decode_fixed dw __09_decode_float - + __01_decode_string: ld e, (hl) inc hl @@ -2643,14 +2643,14 @@ __01_decode_string: ld (__DATA_ADDR), hl ;; Store address of next DATA ex de, hl jp __LOADSTR - + __02_decode_byte: __03_decode_ubyte: ld a, (hl) inc hl ld (__DATA_ADDR), hl ret - + __04_decode_integer: __05_decode_uinteger: ld e, (hl) @@ -2660,7 +2660,7 @@ __05_decode_uinteger: ld (__DATA_ADDR), hl ex de, hl ret - + __06_decode_long: __07_decode_ulong: __08_decode_fixed: @@ -2672,44 +2672,44 @@ __08_decode_fixed: inc bc ld (__DATA_ADDR), bc jp __ILOAD32 - + __09_decode_float: call __LOADF inc hl ld (__DATA_ADDR), hl ld h, a ; returns A in H; sets A free ret - + __DATA_ADDR: ;; Stores current DATA ptr dw __DATA__0 ENDP - - - - - - - - - - + + + + + + + + + + #line 109 "read8.bas" #line 1 "sin.asm" - - - + + + SIN: ; Computes SIN using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 1Fh defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 110 "read8.bas" #line 1 "storef.asm" - + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -2717,7 +2717,7 @@ __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory pop hl ; HL <- IX add hl, de ; HL <- IX + HL pop de - + __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register ex af, af' ld a, (hl) @@ -2725,7 +2725,7 @@ __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address ld h, (hl) ld l, a ; HL = (HL) ex af, af' - + __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), a inc hl @@ -2737,23 +2737,23 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL inc hl ld (hl), b ret - + #line 111 "read8.bas" #line 1 "tan.asm" - - - + + + TAN: ; Computes TAN using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 21h ; TAN defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 112 "read8.bas" - + ZXBASIC_USER_DATA: _v: DEFB 81h diff --git a/tests/functional/read9.asm b/tests/functional/read9.asm index 82d05f175..8a9472b41 100644 --- a/tests/functional/read9.asm +++ b/tests/functional/read9.asm @@ -133,10 +133,10 @@ __DATA__0: __DATA__END: DEFB 00h #line 1 "array.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ------------------------------------------------------------------- ; Simple array Index routine @@ -144,28 +144,28 @@ __DATA__END: ; HL = Start of array memory (First two bytes contains N-1 dimensions) ; Dimension values on the stack, (top of the stack, highest dimension) ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> - + ; For any array of N dimension A(aN-1, ..., a1, a0) ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] ; What I will do here is to calculate the following sequence: ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... - - + + #line 1 "mul16.asm" - + __MUL16: ; Mutiplies HL with the last value stored into de stack ; Works for both signed and unsigned - + PROC - + LOCAL __MUL16LOOP LOCAL __MUL16NOADD - + ex de, hl pop hl ; Return address ex (sp), hl ; CALLEE caller convention - + ;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand ;; ld c, h ;; ld a, l ; C,A => 1st Operand @@ -183,44 +183,44 @@ __MUL16: ; Mutiplies HL with the last value stored into de stack ;;__MUL16NOADD: ;; sla e ;; rl d - ;; + ;; ;; djnz __MUL16LOOP - + __MUL16_FAST: ld b, 16 ld a, d ld c, e ex de, hl ld hl, 0 - + __MUL16LOOP: add hl, hl ; hl << 1 sla c rla ; a,c << 1 jp nc, __MUL16NOADD add hl, de - + __MUL16NOADD: djnz __MUL16LOOP - + ret ; Result in hl (16 lower bits) - + ENDP - + #line 20 "array.asm" - + #line 24 "/src/zxb/trunk/library-asm/array.asm" - + __ARRAY: PROC - + LOCAL LOOP LOCAL ARRAY_END LOCAL RET_ADDRESS ; Stores return address - + ex (sp), hl ; Return address in HL, array address in the stack ld (RET_ADDRESS + 1), hl ; Stores it for later - + exx pop hl ; Will use H'L' as the pointer ld c, (hl) ; Loads Number of dimensions from (hl) @@ -228,23 +228,23 @@ __ARRAY: ld b, (hl) inc hl ; Ready exx - + ld hl, 0 ; BC = Offset "accumulator" - + #line 48 "/src/zxb/trunk/library-asm/array.asm" - + LOOP: pop bc ; Get next index (Ai) from the stack - + #line 60 "/src/zxb/trunk/library-asm/array.asm" - + add hl, bc ; Adds current index - + exx ; Checks if B'C' = 0 ld a, b ; Which means we must exit (last element is not multiplied by anything) or c jr z, ARRAY_END ; if B'Ci == 0 we are done - + ld e, (hl) ; Loads next dimension into D'E' inc hl ld d, (hl) @@ -253,13 +253,13 @@ LOOP: dec bc ; Decrements loop counter exx pop de ; DE = Max bound Number (i-th dimension) - + #line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL #line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP - + ARRAY_END: ld e, (hl) inc hl @@ -267,94 +267,94 @@ ARRAY_END: push hl push de exx - + #line 100 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP - + ex de, hl ld hl, 0 pop bc ld b, c -ARRAY_SIZE_LOOP: +ARRAY_SIZE_LOOP: add hl, de djnz ARRAY_SIZE_LOOP - + ;; Even faster ;pop bc - + ;ld d, h ;ld e, l - + ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;jp z, __ARRAY_FIN - + ;add hl, hl ;dec c ;dec c ;jp z, __ARRAY_FIN - + ;add hl, de - ;__ARRAY_FIN: + ;__ARRAY_FIN: #line 131 "/src/zxb/trunk/library-asm/array.asm" - + pop de add hl, de ; Adds element start - + RET_ADDRESS: ld de, 0 push de ret ; HL = (Start of Elements + Offset) - + ;; Performs a faster multiply for little 16bit numbs LOCAL __FNMUL, __FNMUL2 - + __FNMUL: xor a or d jp nz, __MUL16_FAST - + or e ex de, hl ret z - + cp 33 jp nc, __MUL16_FAST - + ld b, l ld l, h ; HL = 0 - + __FNMUL2: add hl, de djnz __FNMUL2 ret - + ENDP - + #line 120 "read9.bas" #line 1 "iloadf.asm" - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- ((HL)) - + __ILOADF: ld a, (hl) inc hl ld h, (hl) ld l, a - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- (HL) - + __LOADF: ; Loads a 40 bits FP number from address pointed by HL - ld a, (hl) + ld a, (hl) inc hl ld e, (hl) inc hl @@ -364,43 +364,43 @@ __LOADF: ; Loads a 40 bits FP number from address pointed by HL inc hl ld b, (hl) ret - + #line 121 "read9.bas" #line 1 "mulf.asm" - + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -416,7 +416,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 2 "mulf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) ; All of them uses A EDCB registers as 1st paramter. @@ -425,25 +425,25 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; ; Uses CALLEE convention ; ------------------------------------------------------------- - + __MULF: ; Multiplication call __FPSTACK_PUSH2 - + ; ------------- ROM MUL rst 28h - defb 04h ; + defb 04h ; defb 38h; ; END CALC - + jp __FPSTACK_POP - + #line 122 "read9.bas" #line 1 "pow.asm" - - - + + + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) - + ; All of them uses A EDCB registers as 1st paramter. ; For binary operators, the 2n operator must be pushed into the ; stack, in the order A DE BC. @@ -454,35 +454,35 @@ __MULF: ; Multiplication ; 1 st parameter is the BASE (A ED CB) ; 2 nd parameter (Top of the stack) is Exponent ; ------------------------------------------------------------- - + __POW: ; Exponentiation PROC - + call __FPSTACK_PUSH2 - + ; ------------- ROM POW rst 28h defb 01h ; Exchange => 1, Base defb 06h ; POW defb 38h; ; END CALC - + jp __FPSTACK_POP - + ENDP - + #line 123 "read9.bas" #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -490,46 +490,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -542,43 +542,43 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -586,12 +586,12 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -599,51 +599,51 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "in_screen.asm" - + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -652,17 +652,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -670,26 +670,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -703,45 +703,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -752,28 +752,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -781,28 +781,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -811,83 +811,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -896,32 +896,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -931,7 +931,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -939,20 +939,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -962,7 +962,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -973,19 +973,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -995,7 +995,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -1006,19 +1006,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -1028,7 +1028,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -1041,22 +1041,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -1065,79 +1065,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -1146,75 +1146,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -1224,7 +1224,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -1236,16 +1236,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1259,49 +1259,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1312,17 +1312,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1335,27 +1335,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1363,10 +1363,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1383,80 +1383,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1473,8 +1473,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1498,17 +1498,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1519,7 +1519,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1529,21 +1529,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1562,9 +1562,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1589,23 +1589,23 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 124 "read9.bas" #line 1 "printf.asm" - + #line 1 "printstr.asm" - - - - + + + + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1613,25 +1613,25 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1640,41 +1640,41 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1682,25 +1682,25 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1709,39 +1709,39 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -1749,56 +1749,56 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -1807,57 +1807,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -1866,47 +1866,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -1916,51 +1916,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 5 "printstr.asm" - + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1969,62 +1969,62 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 2 "printf.asm" - - - + + + __PRINTF: ; Prints a Fixed point Number stored in C ED LH PROC - + LOCAL RECLAIM2 LOCAL STK_END STK_END EQU 5C65h - + ld hl, (ATTR_T) push hl ; Saves ATTR_T since BUG ROM changes it - + ld hl, (STK_END) push hl ; Stores STK_END - + call __FPSTACK_PUSH ; Push number into stack rst 28h ; # Rom Calculator defb 2Eh ; # STR$(x) defb 38h ; # END CALC call __FPSTACK_POP ; Recovers string parameters to A ED CB - + pop hl ld (STK_END), hl ; Balance STK_END to avoid STR$ bug - + pop hl ld (ATTR_T), hl ; Restores ATTR_T - + ex de, hl ; String position now in HL - + push bc xor a ; Avoid the str to be FREED from heap call __PRINT_STR - pop bc + pop bc inc bc - + jp RECLAIM2 ; Frees TMP Memory - + RECLAIM2 EQU 19E8h - + ENDP - + #line 125 "read9.bas" #line 1 "read_restore.asm" - + ;; This implements READ & RESTORE functions ;; Reads a new element from the DATA Address code ;; Updates the DATA_ADDR read ptr for the next read - + ;; Data codification is 1 byte for type followed by data bytes ;; Byte type is encoded as follows - + ;; 00: End of data ;; 01: String ;; 02: Byte @@ -2035,18 +2035,18 @@ __PRINTF: ; Prints a Fixed point Number stored in C ED LH ;; 07: ULong ;; 08: Fixed ;; 09: Float - + ;; bit7 is set for a parameter-less function ;; In that case, the next two bytes are the ptr of the function to jump - - + + #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -2054,25 +2054,25 @@ __PRINTF: ; Prints a Fixed point Number stored in C ED LH ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -2081,40 +2081,40 @@ __PRINTF: ; Prints a Fixed point Number stored in C ED LH ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - - + + + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -2126,27 +2126,27 @@ __PRINTF: ; Prints a Fixed point Number stored in C ED LH ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -2158,7 +2158,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -2166,15 +2166,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -2199,14 +2199,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -2214,25 +2214,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -2241,30 +2241,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -2272,14 +2272,14 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 24 "read_restore.asm" #line 1 "iload32.asm" - + ; __FASTCALL__ routine which ; loads a 32 bits integer into DE,HL ; stored at position pointed by POINTER HL ; DE,HL <-- (HL) - + __ILOAD32: - ld e, (hl) + ld e, (hl) inc hl ld d, (hl) inc hl @@ -2289,58 +2289,58 @@ __ILOAD32: ld l, a ex de, hl ret - + #line 25 "read_restore.asm" - + #line 1 "ftof16reg.asm" - + #line 1 "ftou32reg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "ftou32reg.asm" - + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) PROC - + LOCAL __IS_FLOAT - + or a - jr nz, __IS_FLOAT + jr nz, __IS_FLOAT ; Here if it is a ZX ROM Integer - + ld h, c ld l, d ld a, e ; Takes sign: FF = -, 0 = + @@ -2348,67 +2348,67 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS inc a jp z, __NEG32 ; Negates if negative ret - + __IS_FLOAT: ; Jumps here if it is a true floating point number - ld h, e + ld h, e push hl ; Stores it for later (Contains Sign in H) - + push de push bc - + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + ;ld a, c ; Get exponent sub 128 ; Exponent -= 128 jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 - + __FTOU32REG_LOOP: exx ; Shift C'B' E'D' << 1, output bit stays in Carry sla d rl e rl b rl c - + exx ; Shift DEHL << 1, inserting the carry on the right rl l rl h rl e rl d - + djnz __FTOU32REG_LOOP - + __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative jp m, __NEG32 ; Negates DEHL - + ret - + ENDP - - + + __FTOU8: ; Converts float in C ED LH to Unsigned byte in A call __FTOU32REG ld a, l ret - + #line 2 "ftof16reg.asm" - + __FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal ; Input FP number in A EDCB (A exponent, EDCB mantissa) - + ld l, a ; Saves exponent for later or d or e @@ -2416,43 +2416,43 @@ __FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal or c ld h, e ret z ; Return if ZERO - + push hl ; Stores it for later (Contains sign in H, exponent in L) - + push de - push bc - + push bc + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + pop bc - + ld a, c ; Get exponent sub 112 ; Exponent -= 128 + 16 - + push bc ; Saves sign in b again - + jp z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jp c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 + 16 (we need to shift 16 bit more) jp __FTOU32REG_LOOP ; proceed as an u32 integer - + #line 27 "read_restore.asm" #line 1 "f16tofreg.asm" - - + + #line 1 "u32tofreg.asm" - - + + __I8TOFREG: ld l, a rlca @@ -2460,35 +2460,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -2496,20 +2496,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -2517,53 +2517,53 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 3 "f16tofreg.asm" - + __F16TOFREG: ; Converts a 16.16 signed fixed point (stored in DEHL) ; to a Floating Point Number returned in (C ED CB) PROC - + LOCAL __F16TOFREG2 - + ld a, d or a ; Test sign - + jp p, __F16TOFREG2 ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __F16TOFREG2 ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - - + + __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in C DE HL - + ld a, d or e or h @@ -2571,45 +2571,45 @@ __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ld b, h ld c, l ret z ; Return 00 0000 0000 if 0 - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 112 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c jp __U32TOFREG_LOOP ; Proceed as an integer - + ENDP - + #line 28 "read_restore.asm" - - - - - - - - - - - - - + + + + + + + + + + + + + ;; Updates restore point to the given HL mem. address __RESTORE: PROC LOCAL __DATA_ADDR - + ld (__DATA_ADDR), hl ret - + ;; Reads a value from the DATA mem area and updates __DATA_ADDR ptr to the ;; next item. On Out Of Data, restarts ;; @@ -2621,7 +2621,7 @@ __READ: LOCAL _from_i16, _from_u16 LOCAL _from_i32, _from_u32 LOCAL _from_fixed, __data_error - + push af ; type of data to read ld hl, (__DATA_ADDR) read_restart: @@ -2629,7 +2629,7 @@ read_restart: or a ; 0 => OUT of data jr nz, cont ;; Signals out of data - + ld hl, __DATA__0 ld (__DATA_ADDR), hl jr read_restart ; Start again @@ -2649,7 +2649,7 @@ cont2: ld de, dynamic_cast push de ; ret address jp (hl) ; "call (hl)" - + ;; Now tries to convert the given result to the expected type or raise an error dynamic_cast: exx @@ -2664,13 +2664,13 @@ dynamic_cast: ;; yes, they are ex af, af' ret - + dynamic_cast2: cp 1 ; Requested a number, but read a string? jr nz, dynamic_cast3 call __MEM_FREE ; Frees str from memory jr __data_error - + dynamic_cast3: exx ld b, a ; Read type @@ -2695,7 +2695,7 @@ dynamic_cast3: ld a, c ; Requested type exx ret - + __data_error: ;; When a data is read, but cannot be converted to the requested type ;; that is, the user asked for a string and we read a number or vice versa @@ -2709,7 +2709,7 @@ __data_error: ld b, a ld c, a ret - + _decode_table: dw _from_i8 dw _from_u8 @@ -2718,13 +2718,13 @@ _decode_table: dw _from_i32 dw _from_u32 dw _from_fixed - + _from_i8: cp 4 jr nc, promote_to_i16 ex af, af' ret ;; Was from Byte to Ubyte - + promote_to_i16: ex af, af' ld l, a @@ -2733,14 +2733,14 @@ promote_to_i16: ld h, a ; copy sgn to h ex af, af' jr _before_from_i16 - + _from_u8: ex af, af' ld l, a ld h, 0 ex af, af' ;; Promoted to i16 - + _before_from_i16: _from_i16: cp 6 @@ -2771,7 +2771,7 @@ _from_fixed: ;; From fixed to float _from_u16: ld de, 0 ; HL 0x0000 => 32 bits jp _from_i32 - + dynamic_cast4: ;; The user type is "shorter" than the read one cp 8 ;; required type @@ -2779,7 +2779,7 @@ dynamic_cast4: ex af, af' exx ;; Ok, we must convert from float to f16 jp __FTOF16REG - + before_to_int: ld a, b ;; read type cp 8 ;; @@ -2807,7 +2807,7 @@ coerce_to_int2: ; At this point we have an u/integer in hl ret nc ; Already done. Return the result ld a, l ; Truncate to byte ret - + no_func: exx ld de, dynamic_cast @@ -2826,7 +2826,7 @@ no_func: exx inc hl ret ; jp (sp) => jump to table[a - 1] - + table: LOCAL __01_decode_string LOCAL __02_decode_byte @@ -2837,7 +2837,7 @@ table: LOCAL __07_decode_ulong LOCAL __08_decode_fixed LOCAL __09_decode_float - + ;; 1 -> Decode string ;; 2, 3 -> Decode Byte, UByte ;; 4, 5 -> Decode Integer, UInteger @@ -2853,7 +2853,7 @@ table: dw __07_decode_ulong dw __08_decode_fixed dw __09_decode_float - + __01_decode_string: ld e, (hl) inc hl @@ -2862,14 +2862,14 @@ __01_decode_string: ld (__DATA_ADDR), hl ;; Store address of next DATA ex de, hl jp __LOADSTR - + __02_decode_byte: __03_decode_ubyte: ld a, (hl) inc hl ld (__DATA_ADDR), hl ret - + __04_decode_integer: __05_decode_uinteger: ld e, (hl) @@ -2879,7 +2879,7 @@ __05_decode_uinteger: ld (__DATA_ADDR), hl ex de, hl ret - + __06_decode_long: __07_decode_ulong: __08_decode_fixed: @@ -2891,44 +2891,44 @@ __08_decode_fixed: inc bc ld (__DATA_ADDR), bc jp __ILOAD32 - + __09_decode_float: call __LOADF inc hl ld (__DATA_ADDR), hl ld h, a ; returns A in H; sets A free ret - + __DATA_ADDR: ;; Stores current DATA ptr dw __DATA__0 ENDP - - - - - - - - - - + + + + + + + + + + #line 126 "read9.bas" #line 1 "sin.asm" - - - + + + SIN: ; Computes SIN using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 1Fh defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 127 "read9.bas" #line 1 "storef.asm" - + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -2936,7 +2936,7 @@ __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory pop hl ; HL <- IX add hl, de ; HL <- IX + HL pop de - + __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register ex af, af' ld a, (hl) @@ -2944,7 +2944,7 @@ __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address ld h, (hl) ld l, a ; HL = (HL) ex af, af' - + __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), a inc hl @@ -2956,23 +2956,23 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL inc hl ld (hl), b ret - + #line 128 "read9.bas" #line 1 "tan.asm" - - - + + + TAN: ; Computes TAN using ROM FP-CALC call __FPSTACK_PUSH - + rst 28h ; ROM CALC defb 21h ; TAN defb 38h ; END CALC - + jp __FPSTACK_POP - + #line 129 "read9.bas" - + ZXBASIC_USER_DATA: _v: DEFB 81h diff --git a/tests/functional/readokdown.asm b/tests/functional/readokdown.asm index 0ff2ed8aa..d36b9f358 100644 --- a/tests/functional/readokdown.asm +++ b/tests/functional/readokdown.asm @@ -106,17 +106,17 @@ __DATA__0: __DATA__END: DEFB 00h #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -124,46 +124,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -176,43 +176,43 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -220,12 +220,12 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -233,51 +233,51 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "in_screen.asm" - + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -286,17 +286,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -304,26 +304,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -337,45 +337,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -386,28 +386,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -415,28 +415,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -445,83 +445,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -530,32 +530,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -565,7 +565,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -573,20 +573,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -596,7 +596,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -607,19 +607,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -629,7 +629,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -640,19 +640,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -662,7 +662,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -675,22 +675,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -699,79 +699,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -780,75 +780,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -858,7 +858,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -870,16 +870,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -893,49 +893,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -946,17 +946,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -969,27 +969,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -997,10 +997,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1017,80 +1017,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1107,8 +1107,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1132,17 +1132,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1153,7 +1153,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1163,21 +1163,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1196,9 +1196,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1223,23 +1223,23 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 93 "readokdown.bas" #line 1 "printf.asm" - + #line 1 "printstr.asm" - - - - + + + + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1247,25 +1247,25 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1274,41 +1274,41 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1316,25 +1316,25 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1343,39 +1343,39 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -1383,56 +1383,56 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -1441,57 +1441,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -1500,47 +1500,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -1550,51 +1550,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 5 "printstr.asm" - + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1603,43 +1603,43 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 2 "printf.asm" #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -1655,68 +1655,68 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 3 "printf.asm" - - + + __PRINTF: ; Prints a Fixed point Number stored in C ED LH PROC - + LOCAL RECLAIM2 LOCAL STK_END STK_END EQU 5C65h - + ld hl, (ATTR_T) push hl ; Saves ATTR_T since BUG ROM changes it - + ld hl, (STK_END) push hl ; Stores STK_END - + call __FPSTACK_PUSH ; Push number into stack rst 28h ; # Rom Calculator defb 2Eh ; # STR$(x) defb 38h ; # END CALC call __FPSTACK_POP ; Recovers string parameters to A ED CB - + pop hl ld (STK_END), hl ; Balance STK_END to avoid STR$ bug - + pop hl ld (ATTR_T), hl ; Restores ATTR_T - + ex de, hl ; String position now in HL - + push bc xor a ; Avoid the str to be FREED from heap call __PRINT_STR - pop bc + pop bc inc bc - + jp RECLAIM2 ; Frees TMP Memory - + RECLAIM2 EQU 19E8h - + ENDP - + #line 94 "readokdown.bas" #line 1 "printf16.asm" - + #line 1 "printnum.asm" - - - - + + + + __PRINTU_START: PROC - + LOCAL __PRINTU_CONT - + ld a, b or a jp nz, __PRINTU_CONT - + ld a, '0' jp __PRINT_DIGIT - - + + __PRINTU_CONT: pop af push bc @@ -1724,33 +1724,33 @@ __PRINTU_CONT: pop bc djnz __PRINTU_CONT ret - + ENDP - - + + __PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers ld a, '-' jp __PRINT_DIGIT - + __PRINT_DIGIT EQU __PRINTCHAR ; PRINTS the char in A register, and puts its attrs - - + + #line 2 "printf16.asm" #line 1 "printi16.asm" - - + + #line 1 "div16.asm" - - ; 16 bit division and modulo functions + + ; 16 bit division and modulo functions ; for both signed and unsigned values - + #line 1 "neg16.asm" - + ; Negates HL value (16 bit) __ABS16: bit 7, h ret z - + __NEGHL: ld a, l ; HL = -HL cpl @@ -1760,23 +1760,23 @@ __NEGHL: ld h, a inc hl ret - + #line 5 "div16.asm" - + __DIVU16: ; 16 bit unsigned division ; HL = Dividend, Stack Top = Divisor - + ; -- OBSOLETE ; Now uses FASTCALL convention ; ex de, hl ; pop hl ; Return address ; ex (sp), hl ; CALLEE Convention - + __DIVU16_FAST: ld a, h ld c, l ld hl, 0 ld b, 16 - + __DIV16LOOP: sll c rla @@ -1785,46 +1785,46 @@ __DIV16LOOP: jr nc, __DIV16NOADD add hl,de dec c - + __DIV16NOADD: djnz __DIV16LOOP - + ex de, hl ld h, a ld l, c - + ret ; HL = quotient, DE = Mudulus - - - + + + __MODU16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVU16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - - + + __DIVI16: ; 16 bit signed division ; --- The following is OBSOLETE --- ; ex de, hl ; pop hl ; ex (sp), hl ; CALLEE Convention - + __DIVI16_FAST: ld a, d xor h ex af, af' ; BIT 7 of a contains result - + bit 7, d ; DE is negative? - jr z, __DIVI16A - + jr z, __DIVI16A + ld a, e ; DE = -DE cpl ld e, a @@ -1832,169 +1832,169 @@ __DIVI16_FAST: cpl ld d, a inc de - + __DIVI16A: bit 7, h ; HL is negative? call nz, __NEGHL - + __DIVI16B: call __DIVU16_FAST ex af, af' - - or a + + or a ret p ; return if positive jp __NEGHL - - + + __MODI16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVI16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - + #line 3 "printi16.asm" - - - + + + __PRINTI16: ; Prints a 16bits signed in HL ; Converts 16 to 32 bits PROC - + LOCAL __PRINTU_LOOP ld a, h or a - + jp p, __PRINTU16 - + call __PRINT_MINUS call __NEGHL - + __PRINTU16: - + ld b, 0 __PRINTU_LOOP: ld a, h or l jp z, __PRINTU_START - + push bc ld de, 10 call __DIVU16_FAST ; Divides by DE. DE = MODULUS at exit. Since < 256, E = Modulus pop bc - + ld a, e or '0' ; Stores ASCII digit (must be print in reversed order) push af inc b jp __PRINTU_LOOP ; Uses JP in loops - + ENDP - + #line 3 "printf16.asm" #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 4 "printf16.asm" - + __PRINTF16: ; Prints a 32bit 16.16 fixed point number PROC - + LOCAL __PRINT_FIX_LOOP LOCAL __PRINTF16_2 - - bit 7, d + + bit 7, d jr z, __PRINTF16_2 call __NEG32 call __PRINT_MINUS - + __PRINTF16_2: push hl ex de, hl call __PRINTU16 ; Prints integer part pop hl - + ld a, h or l ret z ; Returns if integer - + push hl ld a, '.' call __PRINT_DIGIT ; Prints decimal point pop hl - + __PRINT_FIX_LOOP: ld a, h or l ret z ; Returns if no more decimals - + xor a ld d, h ld e, l ; Fast NUM * 10 multiplication - add hl, hl ; + add hl, hl ; adc a, a ; AHL = AHL * 2 (= X * 2) - add hl, hl ; + add hl, hl ; adc a, a ; AHL = AHL * 2 (= X * 4) - - add hl, de ; + + add hl, de ; adc a, 0 ; AHL = AHL + DE (= X * 5) add hl, hl adc a, a ; AHL = AHL * 2 (= X * 10) - + push hl or '0' call __PRINT_DIGIT pop hl jp __PRINT_FIX_LOOP - + ENDP - + #line 95 "readokdown.bas" - + #line 1 "printi32.asm" - - - + + + #line 1 "div32.asm" - - - + + + ; --------------------------------------------------------- __DIVU32: ; 32 bit unsigned division ; DEHL = Dividend, Stack Top = Divisor @@ -2006,7 +2006,7 @@ __DIVU32: ; 32 bit unsigned division pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + __DIVU32START: ; Performs D'E'H'L' / HLDE ; Now switch to DIVIDEND = B'C'BC / DIVISOR = D'E'DE (A / B) push de ; push Lowpart(Q) @@ -2022,9 +2022,9 @@ __DIVU32START: ; Performs D'E'H'L' / HLDE exx pop bc ; Pop HightPart(B) => B = B'C'BC exx - + ld a, 32 ; Loop count - + __DIV32LOOP: sll c ; B'C'BC << 1 ; Output most left bit to carry rl b @@ -2032,29 +2032,29 @@ __DIV32LOOP: rl c rl b exx - + adc hl, hl exx adc hl, hl exx - + sbc hl,de exx sbc hl,de exx jp nc, __DIV32NOADD ; use JP inside a loop for being faster - + add hl, de exx adc hl, de exx dec bc - + __DIV32NOADD: dec a jp nz, __DIV32LOOP ; use JP inside a loop for being faster ; At this point, quotient is stored in B'C'BC and the reminder in H'L'HL - + push hl exx pop de @@ -2064,34 +2064,34 @@ __DIV32NOADD: pop de ; DE = B'C' ld h, b ld l, c ; DEHL = quotient D'E'H'L' = Modulus - + ret ; DEHL = quotient, D'E'H'L' = Modulus - - - + + + __MODU32: ; 32 bit modulus for 32bit unsigned division ; DEHL = Dividend, Stack Top = Divisor (DE, HL) - + exx pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + call __DIVU32START ; At return, modulus is at D'E'H'L' - + __MODU32START: - + exx push de push hl - - exx + + exx pop hl pop de - + ret - - + + __DIVI32: ; 32 bit signed division ; DEHL = Dividend, Stack Top = Divisor ; A = Dividend, B = Divisor => A / B @@ -2099,76 +2099,76 @@ __DIVI32: ; 32 bit signed division pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + __DIVI32START: exx ld a, d ; Save sign ex af, af' bit 7, d ; Negative? call nz, __NEG32 ; Negates DEHL - + exx ; Now works with H'L'D'E' ex af, af' xor h ex af, af' ; Stores sign of the result for later - + bit 7, h ; Negative? ex de, hl ; HLDE = DEHL call nz, __NEG32 - ex de, hl - + ex de, hl + call __DIVU32START ex af, af' ; Recovers sign and 128 ; positive? ret z - + jp __NEG32 ; Negates DEHL and returns from there - - + + __MODI32: ; 32bits signed division modulus exx pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + call __DIVI32START - jp __MODU32START - + jp __MODU32START + #line 4 "printi32.asm" - - - + + + __PRINTI32: ld a, d or a jp p, __PRINTU32 - + call __PRINT_MINUS call __NEG32 - + __PRINTU32: PROC LOCAL __PRINTU_LOOP - + ld b, 0 ; Counter - + __PRINTU_LOOP: ld a, h or l or d or e jp z, __PRINTU_START - + push bc - + ld bc, 0 push bc ld bc, 10 push bc ; Push 00 0A (10 Dec) into the stack = divisor - + call __DIVU32 ; Divides by 32. D'E'H'L' contains modulo (L' since < 10) pop bc - + exx ld a, l or '0' ; Stores ASCII digit (must be print in reversed order) @@ -2176,58 +2176,58 @@ __PRINTU_LOOP: exx inc b jp __PRINTU_LOOP ; Uses JP in loops - + ENDP - + #line 97 "readokdown.bas" #line 1 "printi8.asm" - - + + #line 1 "div8.asm" - + ; -------------------------------- -__DIVU8: ; 8 bit unsigned integer division +__DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A pop hl ; -------------------------------- ex (sp), hl ; CALLEE - + __DIVU8_FAST: ; Does A / H ld l, h ld h, a ; At this point do H / L - + ld b, 8 xor a ; A = 0, Carry Flag = 0 - + __DIV8LOOP: - sla h - rla - cp l + sla h + rla + cp l jr c, __DIV8NOSUB - sub l - inc h - -__DIV8NOSUB: + sub l + inc h + +__DIV8NOSUB: djnz __DIV8LOOP - + ld l, a ; save remainder - ld a, h ; - - ret ; a = Quotient, - - + ld a, h ; + + ret ; a = Quotient, + + ; -------------------------------- __DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A pop hl ; -------------------------------- ex (sp), hl - + __DIVI8_FAST: ld e, a ; store operands for later ld c, h - + or a ; negative? jp p, __DIV8A neg ; Make it positive - + __DIV8A: ex af, af' ld a, h @@ -2235,105 +2235,105 @@ __DIV8A: jp p, __DIV8B neg ld h, a ; make it positive - + __DIV8B: ex af, af' - + call __DIVU8_FAST - + ld a, c xor l ; bit 7 of A = 1 if result is negative - + ld a, h ; Quotient - ret p ; return if positive - + ret p ; return if positive + neg ret - - + + __MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) pop hl ex (sp), hl ; CALLEE - + __MODU8_FAST: ; __FASTCALL__ entry call __DIVU8_FAST ld a, l ; Remainder - + ret ; a = Modulus - - + + __MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) pop hl ex (sp), hl ; CALLEE - + __MODI8_FAST: ; __FASTCALL__ entry call __DIVI8_FAST ld a, l ; remainder - + ret ; a = Modulus - + #line 3 "printi8.asm" - + __PRINTI8: ; Prints an 8 bits number in Accumulator (A) ; Converts 8 to 32 bits or a jp p, __PRINTU8 - + push af call __PRINT_MINUS pop af neg - + __PRINTU8: PROC - + LOCAL __PRINTU_LOOP - + ld b, 0 ; Counter - + __PRINTU_LOOP: or a jp z, __PRINTU_START - + push bc ld h, 10 call __DIVU8_FAST ; Divides by 10. D'E'H'L' contains modulo (L' since < 10) pop bc - + ld a, l or '0' ; Stores ASCII digit (must be print in reversed order) push af ld a, h inc b jp __PRINTU_LOOP ; Uses JP in loops - + ENDP - + #line 98 "readokdown.bas" #line 1 "printu16.asm" - - - + + + #line 99 "readokdown.bas" #line 1 "printu32.asm" - - - + + + #line 100 "readokdown.bas" #line 1 "printu8.asm" - - - + + + #line 101 "readokdown.bas" #line 1 "read_restore.asm" - + ;; This implements READ & RESTORE functions ;; Reads a new element from the DATA Address code ;; Updates the DATA_ADDR read ptr for the next read - + ;; Data codification is 1 byte for type followed by data bytes ;; Byte type is encoded as follows - + ;; 00: End of data ;; 01: String ;; 02: Byte @@ -2344,18 +2344,18 @@ __PRINTU_LOOP: ;; 07: ULong ;; 08: Fixed ;; 09: Float - + ;; bit7 is set for a parameter-less function ;; In that case, the next two bytes are the ptr of the function to jump - - + + #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -2363,25 +2363,25 @@ __PRINTU_LOOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -2390,40 +2390,40 @@ __PRINTU_LOOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - - + + + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -2435,27 +2435,27 @@ __PRINTU_LOOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -2467,7 +2467,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -2475,15 +2475,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -2508,14 +2508,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -2523,25 +2523,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -2550,30 +2550,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -2581,14 +2581,14 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 24 "read_restore.asm" #line 1 "iload32.asm" - + ; __FASTCALL__ routine which ; loads a 32 bits integer into DE,HL ; stored at position pointed by POINTER HL ; DE,HL <-- (HL) - + __ILOAD32: - ld e, (hl) + ld e, (hl) inc hl ld d, (hl) inc hl @@ -2598,28 +2598,28 @@ __ILOAD32: ld l, a ex de, hl ret - + #line 25 "read_restore.asm" #line 1 "iloadf.asm" - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- ((HL)) - + __ILOADF: ld a, (hl) inc hl ld h, (hl) ld l, a - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- (HL) - + __LOADF: ; Loads a 40 bits FP number from address pointed by HL - ld a, (hl) + ld a, (hl) inc hl ld e, (hl) inc hl @@ -2629,25 +2629,25 @@ __LOADF: ; Loads a 40 bits FP number from address pointed by HL inc hl ld b, (hl) ret - + #line 26 "read_restore.asm" #line 1 "ftof16reg.asm" - + #line 1 "ftou32reg.asm" - - - + + + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) PROC - + LOCAL __IS_FLOAT - + or a - jr nz, __IS_FLOAT + jr nz, __IS_FLOAT ; Here if it is a ZX ROM Integer - + ld h, c ld l, d ld a, e ; Takes sign: FF = -, 0 = + @@ -2655,67 +2655,67 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS inc a jp z, __NEG32 ; Negates if negative ret - + __IS_FLOAT: ; Jumps here if it is a true floating point number - ld h, e + ld h, e push hl ; Stores it for later (Contains Sign in H) - + push de push bc - + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + ;ld a, c ; Get exponent sub 128 ; Exponent -= 128 jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 - + __FTOU32REG_LOOP: exx ; Shift C'B' E'D' << 1, output bit stays in Carry sla d rl e rl b rl c - + exx ; Shift DEHL << 1, inserting the carry on the right rl l rl h rl e rl d - + djnz __FTOU32REG_LOOP - + __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative jp m, __NEG32 ; Negates DEHL - + ret - + ENDP - - + + __FTOU8: ; Converts float in C ED LH to Unsigned byte in A call __FTOU32REG ld a, l ret - + #line 2 "ftof16reg.asm" - + __FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal ; Input FP number in A EDCB (A exponent, EDCB mantissa) - + ld l, a ; Saves exponent for later or d or e @@ -2723,43 +2723,43 @@ __FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal or c ld h, e ret z ; Return if ZERO - + push hl ; Stores it for later (Contains sign in H, exponent in L) - + push de - push bc - + push bc + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + pop bc - + ld a, c ; Get exponent sub 112 ; Exponent -= 128 + 16 - + push bc ; Saves sign in b again - + jp z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jp c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 + 16 (we need to shift 16 bit more) jp __FTOU32REG_LOOP ; proceed as an u32 integer - + #line 27 "read_restore.asm" #line 1 "f16tofreg.asm" - - + + #line 1 "u32tofreg.asm" - - + + __I8TOFREG: ld l, a rlca @@ -2767,35 +2767,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -2803,20 +2803,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -2824,53 +2824,53 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 3 "f16tofreg.asm" - + __F16TOFREG: ; Converts a 16.16 signed fixed point (stored in DEHL) ; to a Floating Point Number returned in (C ED CB) PROC - + LOCAL __F16TOFREG2 - + ld a, d or a ; Test sign - + jp p, __F16TOFREG2 ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __F16TOFREG2 ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - - + + __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in C DE HL - + ld a, d or e or h @@ -2878,45 +2878,45 @@ __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ld b, h ld c, l ret z ; Return 00 0000 0000 if 0 - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 112 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c jp __U32TOFREG_LOOP ; Proceed as an integer - + ENDP - + #line 28 "read_restore.asm" - - - - - - - - - - - - - + + + + + + + + + + + + + ;; Updates restore point to the given HL mem. address __RESTORE: PROC LOCAL __DATA_ADDR - + ld (__DATA_ADDR), hl ret - + ;; Reads a value from the DATA mem area and updates __DATA_ADDR ptr to the ;; next item. On Out Of Data, restarts ;; @@ -2928,7 +2928,7 @@ __READ: LOCAL _from_i16, _from_u16 LOCAL _from_i32, _from_u32 LOCAL _from_fixed, __data_error - + push af ; type of data to read ld hl, (__DATA_ADDR) read_restart: @@ -2936,7 +2936,7 @@ read_restart: or a ; 0 => OUT of data jr nz, cont ;; Signals out of data - + ld hl, __DATA__0 ld (__DATA_ADDR), hl jr read_restart ; Start again @@ -2956,7 +2956,7 @@ cont2: ld de, dynamic_cast push de ; ret address jp (hl) ; "call (hl)" - + ;; Now tries to convert the given result to the expected type or raise an error dynamic_cast: exx @@ -2971,13 +2971,13 @@ dynamic_cast: ;; yes, they are ex af, af' ret - + dynamic_cast2: cp 1 ; Requested a number, but read a string? jr nz, dynamic_cast3 call __MEM_FREE ; Frees str from memory jr __data_error - + dynamic_cast3: exx ld b, a ; Read type @@ -3002,7 +3002,7 @@ dynamic_cast3: ld a, c ; Requested type exx ret - + __data_error: ;; When a data is read, but cannot be converted to the requested type ;; that is, the user asked for a string and we read a number or vice versa @@ -3016,7 +3016,7 @@ __data_error: ld b, a ld c, a ret - + _decode_table: dw _from_i8 dw _from_u8 @@ -3025,13 +3025,13 @@ _decode_table: dw _from_i32 dw _from_u32 dw _from_fixed - + _from_i8: cp 4 jr nc, promote_to_i16 ex af, af' ret ;; Was from Byte to Ubyte - + promote_to_i16: ex af, af' ld l, a @@ -3040,14 +3040,14 @@ promote_to_i16: ld h, a ; copy sgn to h ex af, af' jr _before_from_i16 - + _from_u8: ex af, af' ld l, a ld h, 0 ex af, af' ;; Promoted to i16 - + _before_from_i16: _from_i16: cp 6 @@ -3078,7 +3078,7 @@ _from_fixed: ;; From fixed to float _from_u16: ld de, 0 ; HL 0x0000 => 32 bits jp _from_i32 - + dynamic_cast4: ;; The user type is "shorter" than the read one cp 8 ;; required type @@ -3086,7 +3086,7 @@ dynamic_cast4: ex af, af' exx ;; Ok, we must convert from float to f16 jp __FTOF16REG - + before_to_int: ld a, b ;; read type cp 8 ;; @@ -3114,7 +3114,7 @@ coerce_to_int2: ; At this point we have an u/integer in hl ret nc ; Already done. Return the result ld a, l ; Truncate to byte ret - + no_func: exx ld de, dynamic_cast @@ -3133,7 +3133,7 @@ no_func: exx inc hl ret ; jp (sp) => jump to table[a - 1] - + table: LOCAL __01_decode_string LOCAL __02_decode_byte @@ -3144,7 +3144,7 @@ table: LOCAL __07_decode_ulong LOCAL __08_decode_fixed LOCAL __09_decode_float - + ;; 1 -> Decode string ;; 2, 3 -> Decode Byte, UByte ;; 4, 5 -> Decode Integer, UInteger @@ -3160,7 +3160,7 @@ table: dw __07_decode_ulong dw __08_decode_fixed dw __09_decode_float - + __01_decode_string: ld e, (hl) inc hl @@ -3169,14 +3169,14 @@ __01_decode_string: ld (__DATA_ADDR), hl ;; Store address of next DATA ex de, hl jp __LOADSTR - + __02_decode_byte: __03_decode_ubyte: ld a, (hl) inc hl ld (__DATA_ADDR), hl ret - + __04_decode_integer: __05_decode_uinteger: ld e, (hl) @@ -3186,7 +3186,7 @@ __05_decode_uinteger: ld (__DATA_ADDR), hl ex de, hl ret - + __06_decode_long: __07_decode_ulong: __08_decode_fixed: @@ -3198,30 +3198,30 @@ __08_decode_fixed: inc bc ld (__DATA_ADDR), bc jp __ILOAD32 - + __09_decode_float: call __LOADF inc hl ld (__DATA_ADDR), hl ld h, a ; returns A in H; sets A free ret - + __DATA_ADDR: ;; Stores current DATA ptr dw __DATA__0 ENDP - - - - - - - - - - + + + + + + + + + + #line 102 "readokdown.bas" #line 1 "storef.asm" - + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -3229,7 +3229,7 @@ __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory pop hl ; HL <- IX add hl, de ; HL <- IX + HL pop de - + __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register ex af, af' ld a, (hl) @@ -3237,7 +3237,7 @@ __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address ld h, (hl) ld l, a ; HL = (HL) ex af, af' - + __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), a inc hl @@ -3249,9 +3249,9 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL inc hl ld (hl), b ret - + #line 103 "readokdown.bas" - + ZXBASIC_USER_DATA: _i8: DEFB 00 diff --git a/tests/functional/readokup.asm b/tests/functional/readokup.asm index 5db26259d..6b5193922 100644 --- a/tests/functional/readokup.asm +++ b/tests/functional/readokup.asm @@ -105,17 +105,17 @@ __DATA__0: __DATA__END: DEFB 00h #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -123,46 +123,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -175,43 +175,43 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -219,12 +219,12 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -232,51 +232,51 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "in_screen.asm" - + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -285,17 +285,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -303,26 +303,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -336,45 +336,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -385,28 +385,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -414,28 +414,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -444,83 +444,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -529,32 +529,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -564,7 +564,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -572,20 +572,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -595,7 +595,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -606,19 +606,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -628,7 +628,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -639,19 +639,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -661,7 +661,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -674,22 +674,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -698,79 +698,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -779,75 +779,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -857,7 +857,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -869,16 +869,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -892,49 +892,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -945,17 +945,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -968,27 +968,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -996,10 +996,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1016,80 +1016,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1106,8 +1106,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1131,17 +1131,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1152,7 +1152,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1162,21 +1162,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1195,9 +1195,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1222,23 +1222,23 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 92 "readokup.bas" #line 1 "printf.asm" - + #line 1 "printstr.asm" - - - - + + + + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1246,25 +1246,25 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1273,41 +1273,41 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1315,25 +1315,25 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1342,39 +1342,39 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -1382,56 +1382,56 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -1440,57 +1440,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -1499,47 +1499,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -1549,51 +1549,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 5 "printstr.asm" - + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1602,43 +1602,43 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 2 "printf.asm" #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -1654,68 +1654,68 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 3 "printf.asm" - - + + __PRINTF: ; Prints a Fixed point Number stored in C ED LH PROC - + LOCAL RECLAIM2 LOCAL STK_END STK_END EQU 5C65h - + ld hl, (ATTR_T) push hl ; Saves ATTR_T since BUG ROM changes it - + ld hl, (STK_END) push hl ; Stores STK_END - + call __FPSTACK_PUSH ; Push number into stack rst 28h ; # Rom Calculator defb 2Eh ; # STR$(x) defb 38h ; # END CALC call __FPSTACK_POP ; Recovers string parameters to A ED CB - + pop hl ld (STK_END), hl ; Balance STK_END to avoid STR$ bug - + pop hl ld (ATTR_T), hl ; Restores ATTR_T - + ex de, hl ; String position now in HL - + push bc xor a ; Avoid the str to be FREED from heap call __PRINT_STR - pop bc + pop bc inc bc - + jp RECLAIM2 ; Frees TMP Memory - + RECLAIM2 EQU 19E8h - + ENDP - + #line 93 "readokup.bas" #line 1 "printf16.asm" - + #line 1 "printnum.asm" - - - - + + + + __PRINTU_START: PROC - + LOCAL __PRINTU_CONT - + ld a, b or a jp nz, __PRINTU_CONT - + ld a, '0' jp __PRINT_DIGIT - - + + __PRINTU_CONT: pop af push bc @@ -1723,33 +1723,33 @@ __PRINTU_CONT: pop bc djnz __PRINTU_CONT ret - + ENDP - - + + __PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers ld a, '-' jp __PRINT_DIGIT - + __PRINT_DIGIT EQU __PRINTCHAR ; PRINTS the char in A register, and puts its attrs - - + + #line 2 "printf16.asm" #line 1 "printi16.asm" - - + + #line 1 "div16.asm" - - ; 16 bit division and modulo functions + + ; 16 bit division and modulo functions ; for both signed and unsigned values - + #line 1 "neg16.asm" - + ; Negates HL value (16 bit) __ABS16: bit 7, h ret z - + __NEGHL: ld a, l ; HL = -HL cpl @@ -1759,23 +1759,23 @@ __NEGHL: ld h, a inc hl ret - + #line 5 "div16.asm" - + __DIVU16: ; 16 bit unsigned division ; HL = Dividend, Stack Top = Divisor - + ; -- OBSOLETE ; Now uses FASTCALL convention ; ex de, hl ; pop hl ; Return address ; ex (sp), hl ; CALLEE Convention - + __DIVU16_FAST: ld a, h ld c, l ld hl, 0 ld b, 16 - + __DIV16LOOP: sll c rla @@ -1784,46 +1784,46 @@ __DIV16LOOP: jr nc, __DIV16NOADD add hl,de dec c - + __DIV16NOADD: djnz __DIV16LOOP - + ex de, hl ld h, a ld l, c - + ret ; HL = quotient, DE = Mudulus - - - + + + __MODU16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVU16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - - + + __DIVI16: ; 16 bit signed division ; --- The following is OBSOLETE --- ; ex de, hl ; pop hl ; ex (sp), hl ; CALLEE Convention - + __DIVI16_FAST: ld a, d xor h ex af, af' ; BIT 7 of a contains result - + bit 7, d ; DE is negative? - jr z, __DIVI16A - + jr z, __DIVI16A + ld a, e ; DE = -DE cpl ld e, a @@ -1831,169 +1831,169 @@ __DIVI16_FAST: cpl ld d, a inc de - + __DIVI16A: bit 7, h ; HL is negative? call nz, __NEGHL - + __DIVI16B: call __DIVU16_FAST ex af, af' - - or a + + or a ret p ; return if positive jp __NEGHL - - + + __MODI16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVI16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - + #line 3 "printi16.asm" - - - + + + __PRINTI16: ; Prints a 16bits signed in HL ; Converts 16 to 32 bits PROC - + LOCAL __PRINTU_LOOP ld a, h or a - + jp p, __PRINTU16 - + call __PRINT_MINUS call __NEGHL - + __PRINTU16: - + ld b, 0 __PRINTU_LOOP: ld a, h or l jp z, __PRINTU_START - + push bc ld de, 10 call __DIVU16_FAST ; Divides by DE. DE = MODULUS at exit. Since < 256, E = Modulus pop bc - + ld a, e or '0' ; Stores ASCII digit (must be print in reversed order) push af inc b jp __PRINTU_LOOP ; Uses JP in loops - + ENDP - + #line 3 "printf16.asm" #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 4 "printf16.asm" - + __PRINTF16: ; Prints a 32bit 16.16 fixed point number PROC - + LOCAL __PRINT_FIX_LOOP LOCAL __PRINTF16_2 - - bit 7, d + + bit 7, d jr z, __PRINTF16_2 call __NEG32 call __PRINT_MINUS - + __PRINTF16_2: push hl ex de, hl call __PRINTU16 ; Prints integer part pop hl - + ld a, h or l ret z ; Returns if integer - + push hl ld a, '.' call __PRINT_DIGIT ; Prints decimal point pop hl - + __PRINT_FIX_LOOP: ld a, h or l ret z ; Returns if no more decimals - + xor a ld d, h ld e, l ; Fast NUM * 10 multiplication - add hl, hl ; + add hl, hl ; adc a, a ; AHL = AHL * 2 (= X * 2) - add hl, hl ; + add hl, hl ; adc a, a ; AHL = AHL * 2 (= X * 4) - - add hl, de ; + + add hl, de ; adc a, 0 ; AHL = AHL + DE (= X * 5) add hl, hl adc a, a ; AHL = AHL * 2 (= X * 10) - + push hl or '0' call __PRINT_DIGIT pop hl jp __PRINT_FIX_LOOP - + ENDP - + #line 94 "readokup.bas" - + #line 1 "printi32.asm" - - - + + + #line 1 "div32.asm" - - - + + + ; --------------------------------------------------------- __DIVU32: ; 32 bit unsigned division ; DEHL = Dividend, Stack Top = Divisor @@ -2005,7 +2005,7 @@ __DIVU32: ; 32 bit unsigned division pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + __DIVU32START: ; Performs D'E'H'L' / HLDE ; Now switch to DIVIDEND = B'C'BC / DIVISOR = D'E'DE (A / B) push de ; push Lowpart(Q) @@ -2021,9 +2021,9 @@ __DIVU32START: ; Performs D'E'H'L' / HLDE exx pop bc ; Pop HightPart(B) => B = B'C'BC exx - + ld a, 32 ; Loop count - + __DIV32LOOP: sll c ; B'C'BC << 1 ; Output most left bit to carry rl b @@ -2031,29 +2031,29 @@ __DIV32LOOP: rl c rl b exx - + adc hl, hl exx adc hl, hl exx - + sbc hl,de exx sbc hl,de exx jp nc, __DIV32NOADD ; use JP inside a loop for being faster - + add hl, de exx adc hl, de exx dec bc - + __DIV32NOADD: dec a jp nz, __DIV32LOOP ; use JP inside a loop for being faster ; At this point, quotient is stored in B'C'BC and the reminder in H'L'HL - + push hl exx pop de @@ -2063,34 +2063,34 @@ __DIV32NOADD: pop de ; DE = B'C' ld h, b ld l, c ; DEHL = quotient D'E'H'L' = Modulus - + ret ; DEHL = quotient, D'E'H'L' = Modulus - - - + + + __MODU32: ; 32 bit modulus for 32bit unsigned division ; DEHL = Dividend, Stack Top = Divisor (DE, HL) - + exx pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + call __DIVU32START ; At return, modulus is at D'E'H'L' - + __MODU32START: - + exx push de push hl - - exx + + exx pop hl pop de - + ret - - + + __DIVI32: ; 32 bit signed division ; DEHL = Dividend, Stack Top = Divisor ; A = Dividend, B = Divisor => A / B @@ -2098,76 +2098,76 @@ __DIVI32: ; 32 bit signed division pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + __DIVI32START: exx ld a, d ; Save sign ex af, af' bit 7, d ; Negative? call nz, __NEG32 ; Negates DEHL - + exx ; Now works with H'L'D'E' ex af, af' xor h ex af, af' ; Stores sign of the result for later - + bit 7, h ; Negative? ex de, hl ; HLDE = DEHL call nz, __NEG32 - ex de, hl - + ex de, hl + call __DIVU32START ex af, af' ; Recovers sign and 128 ; positive? ret z - + jp __NEG32 ; Negates DEHL and returns from there - - + + __MODI32: ; 32bits signed division modulus exx pop hl ; return address pop de ; low part ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend - + call __DIVI32START - jp __MODU32START - + jp __MODU32START + #line 4 "printi32.asm" - - - + + + __PRINTI32: ld a, d or a jp p, __PRINTU32 - + call __PRINT_MINUS call __NEG32 - + __PRINTU32: PROC LOCAL __PRINTU_LOOP - + ld b, 0 ; Counter - + __PRINTU_LOOP: ld a, h or l or d or e jp z, __PRINTU_START - + push bc - + ld bc, 0 push bc ld bc, 10 push bc ; Push 00 0A (10 Dec) into the stack = divisor - + call __DIVU32 ; Divides by 32. D'E'H'L' contains modulo (L' since < 10) pop bc - + exx ld a, l or '0' ; Stores ASCII digit (must be print in reversed order) @@ -2175,58 +2175,58 @@ __PRINTU_LOOP: exx inc b jp __PRINTU_LOOP ; Uses JP in loops - + ENDP - + #line 96 "readokup.bas" #line 1 "printi8.asm" - - + + #line 1 "div8.asm" - + ; -------------------------------- -__DIVU8: ; 8 bit unsigned integer division +__DIVU8: ; 8 bit unsigned integer division ; Divides (Top of stack, High Byte) / A pop hl ; -------------------------------- ex (sp), hl ; CALLEE - + __DIVU8_FAST: ; Does A / H ld l, h ld h, a ; At this point do H / L - + ld b, 8 xor a ; A = 0, Carry Flag = 0 - + __DIV8LOOP: - sla h - rla - cp l + sla h + rla + cp l jr c, __DIV8NOSUB - sub l - inc h - -__DIV8NOSUB: + sub l + inc h + +__DIV8NOSUB: djnz __DIV8LOOP - + ld l, a ; save remainder - ld a, h ; - - ret ; a = Quotient, - - + ld a, h ; + + ret ; a = Quotient, + + ; -------------------------------- __DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A pop hl ; -------------------------------- ex (sp), hl - + __DIVI8_FAST: ld e, a ; store operands for later ld c, h - + or a ; negative? jp p, __DIV8A neg ; Make it positive - + __DIV8A: ex af, af' ld a, h @@ -2234,105 +2234,105 @@ __DIV8A: jp p, __DIV8B neg ld h, a ; make it positive - + __DIV8B: ex af, af' - + call __DIVU8_FAST - + ld a, c xor l ; bit 7 of A = 1 if result is negative - + ld a, h ; Quotient - ret p ; return if positive - + ret p ; return if positive + neg ret - - + + __MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) pop hl ex (sp), hl ; CALLEE - + __MODU8_FAST: ; __FASTCALL__ entry call __DIVU8_FAST ld a, l ; Remainder - + ret ; a = Modulus - - + + __MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) pop hl ex (sp), hl ; CALLEE - + __MODI8_FAST: ; __FASTCALL__ entry call __DIVI8_FAST ld a, l ; remainder - + ret ; a = Modulus - + #line 3 "printi8.asm" - + __PRINTI8: ; Prints an 8 bits number in Accumulator (A) ; Converts 8 to 32 bits or a jp p, __PRINTU8 - + push af call __PRINT_MINUS pop af neg - + __PRINTU8: PROC - + LOCAL __PRINTU_LOOP - + ld b, 0 ; Counter - + __PRINTU_LOOP: or a jp z, __PRINTU_START - + push bc ld h, 10 call __DIVU8_FAST ; Divides by 10. D'E'H'L' contains modulo (L' since < 10) pop bc - + ld a, l or '0' ; Stores ASCII digit (must be print in reversed order) push af ld a, h inc b jp __PRINTU_LOOP ; Uses JP in loops - + ENDP - + #line 97 "readokup.bas" #line 1 "printu16.asm" - - - + + + #line 98 "readokup.bas" #line 1 "printu32.asm" - - - + + + #line 99 "readokup.bas" #line 1 "printu8.asm" - - - + + + #line 100 "readokup.bas" #line 1 "read_restore.asm" - + ;; This implements READ & RESTORE functions ;; Reads a new element from the DATA Address code ;; Updates the DATA_ADDR read ptr for the next read - + ;; Data codification is 1 byte for type followed by data bytes ;; Byte type is encoded as follows - + ;; 00: End of data ;; 01: String ;; 02: Byte @@ -2343,18 +2343,18 @@ __PRINTU_LOOP: ;; 07: ULong ;; 08: Fixed ;; 09: Float - + ;; bit7 is set for a parameter-less function ;; In that case, the next two bytes are the ptr of the function to jump - - + + #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -2362,25 +2362,25 @@ __PRINTU_LOOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -2389,40 +2389,40 @@ __PRINTU_LOOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - - + + + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -2434,27 +2434,27 @@ __PRINTU_LOOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -2466,7 +2466,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -2474,15 +2474,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -2507,14 +2507,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -2522,25 +2522,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -2549,30 +2549,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -2580,14 +2580,14 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 24 "read_restore.asm" #line 1 "iload32.asm" - + ; __FASTCALL__ routine which ; loads a 32 bits integer into DE,HL ; stored at position pointed by POINTER HL ; DE,HL <-- (HL) - + __ILOAD32: - ld e, (hl) + ld e, (hl) inc hl ld d, (hl) inc hl @@ -2597,28 +2597,28 @@ __ILOAD32: ld l, a ex de, hl ret - + #line 25 "read_restore.asm" #line 1 "iloadf.asm" - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- ((HL)) - + __ILOADF: ld a, (hl) inc hl ld h, (hl) ld l, a - + ; __FASTCALL__ routine which ; loads a 40 bits floating point into A ED CB ; stored at position pointed by POINTER HL ;A DE, BC <-- (HL) - + __LOADF: ; Loads a 40 bits FP number from address pointed by HL - ld a, (hl) + ld a, (hl) inc hl ld e, (hl) inc hl @@ -2628,25 +2628,25 @@ __LOADF: ; Loads a 40 bits FP number from address pointed by HL inc hl ld b, (hl) ret - + #line 26 "read_restore.asm" #line 1 "ftof16reg.asm" - + #line 1 "ftou32reg.asm" - - - + + + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) PROC - + LOCAL __IS_FLOAT - + or a - jr nz, __IS_FLOAT + jr nz, __IS_FLOAT ; Here if it is a ZX ROM Integer - + ld h, c ld l, d ld a, e ; Takes sign: FF = -, 0 = + @@ -2654,67 +2654,67 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS inc a jp z, __NEG32 ; Negates if negative ret - + __IS_FLOAT: ; Jumps here if it is a true floating point number - ld h, e + ld h, e push hl ; Stores it for later (Contains Sign in H) - + push de push bc - + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + ;ld a, c ; Get exponent sub 128 ; Exponent -= 128 jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 - + __FTOU32REG_LOOP: exx ; Shift C'B' E'D' << 1, output bit stays in Carry sla d rl e rl b rl c - + exx ; Shift DEHL << 1, inserting the carry on the right rl l rl h rl e rl d - + djnz __FTOU32REG_LOOP - + __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative jp m, __NEG32 ; Negates DEHL - + ret - + ENDP - - + + __FTOU8: ; Converts float in C ED LH to Unsigned byte in A call __FTOU32REG ld a, l ret - + #line 2 "ftof16reg.asm" - + __FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal ; Input FP number in A EDCB (A exponent, EDCB mantissa) - + ld l, a ; Saves exponent for later or d or e @@ -2722,43 +2722,43 @@ __FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal or c ld h, e ret z ; Return if ZERO - + push hl ; Stores it for later (Contains sign in H, exponent in L) - + push de - push bc - + push bc + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + pop bc - + ld a, c ; Get exponent sub 112 ; Exponent -= 128 + 16 - + push bc ; Saves sign in b again - + jp z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jp c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 + 16 (we need to shift 16 bit more) jp __FTOU32REG_LOOP ; proceed as an u32 integer - + #line 27 "read_restore.asm" #line 1 "f16tofreg.asm" - - + + #line 1 "u32tofreg.asm" - - + + __I8TOFREG: ld l, a rlca @@ -2766,35 +2766,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -2802,20 +2802,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -2823,53 +2823,53 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 3 "f16tofreg.asm" - + __F16TOFREG: ; Converts a 16.16 signed fixed point (stored in DEHL) ; to a Floating Point Number returned in (C ED CB) PROC - + LOCAL __F16TOFREG2 - + ld a, d or a ; Test sign - + jp p, __F16TOFREG2 ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __F16TOFREG2 ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - - + + __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in C DE HL - + ld a, d or e or h @@ -2877,45 +2877,45 @@ __F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) ld b, h ld c, l ret z ; Return 00 0000 0000 if 0 - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 112 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c jp __U32TOFREG_LOOP ; Proceed as an integer - + ENDP - + #line 28 "read_restore.asm" - - - - - - - - - - - - - + + + + + + + + + + + + + ;; Updates restore point to the given HL mem. address __RESTORE: PROC LOCAL __DATA_ADDR - + ld (__DATA_ADDR), hl ret - + ;; Reads a value from the DATA mem area and updates __DATA_ADDR ptr to the ;; next item. On Out Of Data, restarts ;; @@ -2927,7 +2927,7 @@ __READ: LOCAL _from_i16, _from_u16 LOCAL _from_i32, _from_u32 LOCAL _from_fixed, __data_error - + push af ; type of data to read ld hl, (__DATA_ADDR) read_restart: @@ -2935,7 +2935,7 @@ read_restart: or a ; 0 => OUT of data jr nz, cont ;; Signals out of data - + ld hl, __DATA__0 ld (__DATA_ADDR), hl jr read_restart ; Start again @@ -2955,7 +2955,7 @@ cont2: ld de, dynamic_cast push de ; ret address jp (hl) ; "call (hl)" - + ;; Now tries to convert the given result to the expected type or raise an error dynamic_cast: exx @@ -2970,13 +2970,13 @@ dynamic_cast: ;; yes, they are ex af, af' ret - + dynamic_cast2: cp 1 ; Requested a number, but read a string? jr nz, dynamic_cast3 call __MEM_FREE ; Frees str from memory jr __data_error - + dynamic_cast3: exx ld b, a ; Read type @@ -3001,7 +3001,7 @@ dynamic_cast3: ld a, c ; Requested type exx ret - + __data_error: ;; When a data is read, but cannot be converted to the requested type ;; that is, the user asked for a string and we read a number or vice versa @@ -3015,7 +3015,7 @@ __data_error: ld b, a ld c, a ret - + _decode_table: dw _from_i8 dw _from_u8 @@ -3024,13 +3024,13 @@ _decode_table: dw _from_i32 dw _from_u32 dw _from_fixed - + _from_i8: cp 4 jr nc, promote_to_i16 ex af, af' ret ;; Was from Byte to Ubyte - + promote_to_i16: ex af, af' ld l, a @@ -3039,14 +3039,14 @@ promote_to_i16: ld h, a ; copy sgn to h ex af, af' jr _before_from_i16 - + _from_u8: ex af, af' ld l, a ld h, 0 ex af, af' ;; Promoted to i16 - + _before_from_i16: _from_i16: cp 6 @@ -3077,7 +3077,7 @@ _from_fixed: ;; From fixed to float _from_u16: ld de, 0 ; HL 0x0000 => 32 bits jp _from_i32 - + dynamic_cast4: ;; The user type is "shorter" than the read one cp 8 ;; required type @@ -3085,7 +3085,7 @@ dynamic_cast4: ex af, af' exx ;; Ok, we must convert from float to f16 jp __FTOF16REG - + before_to_int: ld a, b ;; read type cp 8 ;; @@ -3113,7 +3113,7 @@ coerce_to_int2: ; At this point we have an u/integer in hl ret nc ; Already done. Return the result ld a, l ; Truncate to byte ret - + no_func: exx ld de, dynamic_cast @@ -3132,7 +3132,7 @@ no_func: exx inc hl ret ; jp (sp) => jump to table[a - 1] - + table: LOCAL __01_decode_string LOCAL __02_decode_byte @@ -3143,7 +3143,7 @@ table: LOCAL __07_decode_ulong LOCAL __08_decode_fixed LOCAL __09_decode_float - + ;; 1 -> Decode string ;; 2, 3 -> Decode Byte, UByte ;; 4, 5 -> Decode Integer, UInteger @@ -3159,7 +3159,7 @@ table: dw __07_decode_ulong dw __08_decode_fixed dw __09_decode_float - + __01_decode_string: ld e, (hl) inc hl @@ -3168,14 +3168,14 @@ __01_decode_string: ld (__DATA_ADDR), hl ;; Store address of next DATA ex de, hl jp __LOADSTR - + __02_decode_byte: __03_decode_ubyte: ld a, (hl) inc hl ld (__DATA_ADDR), hl ret - + __04_decode_integer: __05_decode_uinteger: ld e, (hl) @@ -3185,7 +3185,7 @@ __05_decode_uinteger: ld (__DATA_ADDR), hl ex de, hl ret - + __06_decode_long: __07_decode_ulong: __08_decode_fixed: @@ -3197,30 +3197,30 @@ __08_decode_fixed: inc bc ld (__DATA_ADDR), bc jp __ILOAD32 - + __09_decode_float: call __LOADF inc hl ld (__DATA_ADDR), hl ld h, a ; returns A in H; sets A free ret - + __DATA_ADDR: ;; Stores current DATA ptr dw __DATA__0 ENDP - - - - - - - - - - + + + + + + + + + + #line 101 "readokup.bas" #line 1 "storef.asm" - + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -3228,7 +3228,7 @@ __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory pop hl ; HL <- IX add hl, de ; HL <- IX + HL pop de - + __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register ex af, af' ld a, (hl) @@ -3236,7 +3236,7 @@ __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address ld h, (hl) ld l, a ; HL = (HL) ex af, af' - + __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), a inc hl @@ -3248,9 +3248,9 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL inc hl ld (hl), b ret - + #line 102 "readokup.bas" - + ZXBASIC_USER_DATA: _i8: DEFB 00 diff --git a/tests/functional/recur0.asm b/tests/functional/recur0.asm index 42b8e85d7..53d4bd283 100644 --- a/tests/functional/recur0.asm +++ b/tests/functional/recur0.asm @@ -35,7 +35,7 @@ _Test__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/refconstparam.asm b/tests/functional/refconstparam.asm index 83d9c971c..b6674b390 100644 --- a/tests/functional/refconstparam.asm +++ b/tests/functional/refconstparam.asm @@ -44,7 +44,7 @@ _x__leave: ex (sp), hl exx ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/refconstparam2.asm b/tests/functional/refconstparam2.asm index 83d9c971c..b6674b390 100644 --- a/tests/functional/refconstparam2.asm +++ b/tests/functional/refconstparam2.asm @@ -44,7 +44,7 @@ _x__leave: ex (sp), hl exx ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/refconstparam4.asm b/tests/functional/refconstparam4.asm index d10eea80c..f8f398b90 100644 --- a/tests/functional/refconstparam4.asm +++ b/tests/functional/refconstparam4.asm @@ -43,7 +43,7 @@ _x__leave: ex (sp), hl exx ret - + ZXBASIC_USER_DATA: _b: DEFB 00, 00 diff --git a/tests/functional/refconstparam5.asm b/tests/functional/refconstparam5.asm index 4185e5b8e..503001f25 100644 --- a/tests/functional/refconstparam5.asm +++ b/tests/functional/refconstparam5.asm @@ -42,7 +42,7 @@ _x__leave: ex (sp), hl exx ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/refconstparam6.asm b/tests/functional/refconstparam6.asm index 4185e5b8e..503001f25 100644 --- a/tests/functional/refconstparam6.asm +++ b/tests/functional/refconstparam6.asm @@ -42,7 +42,7 @@ _x__leave: ex (sp), hl exx ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/save01.asm b/tests/functional/save01.asm index b3f59de4b..bab7d214f 100644 --- a/tests/functional/save01.asm +++ b/tests/functional/save01.asm @@ -48,12 +48,12 @@ __LABEL0: DEFB 74h DEFB 73h #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -61,25 +61,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -88,51 +88,51 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -140,12 +140,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -153,7 +153,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -161,10 +161,10 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -172,25 +172,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -199,39 +199,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -239,57 +239,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -301,27 +301,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -333,7 +333,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -341,15 +341,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -374,14 +374,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -389,25 +389,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -416,30 +416,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -447,75 +447,75 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 36 "save01.bas" #line 1 "save.asm" - + ; Save code "XXX" at address YYY of length ZZZ ; Parameters in the stack are XXX (16 bit) address of string name ; (only first 12 chars will be taken into account) ; YYY and ZZZ are 16 bit on top of the stack. - - - + + + SAVE_CODE: - + PROC - + LOCAL MEMBOT LOCAL SAVE_CONT LOCAL ROM_SAVE LOCAL __ERR_EMPTY LOCAL SAVE_STOP - - ROM_SAVE EQU 0970h + + ROM_SAVE EQU 0970h MEMBOT EQU 23698 ; Use the CALC mem to store header - + pop hl ; Return address pop bc ; data length in bytes pop de ; address start ex (sp), hl ; CALLE => now hl = String - + ; This function will call the ROM SAVE CODE Routine ; Parameters in the stack are HL => String with SAVE name ; (only first 12 chars will be taken into account) ; DE = START address of CODE to save ; BC = Length of data in bytes - + __SAVE_CODE: ; INLINE version ld a, b or c ret z ; Return if block length == 0 - + push ix ld a, h or l jr z, __ERR_EMPTY ; Return if NULL STRING - + ld ix, MEMBOT ld (ix + 00), 3 ; CODE - + ld (ix + 11), c ld (ix + 12), b ; Store long in bytes ld (ix + 13), e ld (ix + 14), d ; Store address in bytes - + push hl ld bc, 9 ld HL, MEMBOT + 1 ld DE, MEMBOT + 2 ld (hl), ' ' ldir ; Fill the filename with blanks - pop hl - + pop hl + ld c, (hl) inc hl ld b, (hl) inc hl ld a, b or c - + __ERR_EMPTY: ld a, ERROR_InvalidFileName jr z, SAVE_STOP ; Return if str len == 0 - + ex de, hl ; Saves HL in DE ld hl, 10 or a @@ -523,27 +523,27 @@ __ERR_EMPTY: ex de, hl jr nc, SAVE_CONT ; Ok BC <= 10 ld bc, 10 ; BC at most 10 chars - + SAVE_CONT: ld de, MEMBOT + 1 ldir ; Copy String block NAME ld l, (ix + 13) - ld h, (ix + 14) ; Restores start of bytes - + ld h, (ix + 14) ; Restores start of bytes + call ROM_SAVE ; Recovers ECHO_E since ROM SAVE changes it ld hl, 1821h ld (23682), hl pop ix ret - + SAVE_STOP: pop ix jp __STOP - + ENDP #line 37 "save01.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/save02.asm b/tests/functional/save02.asm index 6a8dfb644..57f739883 100644 --- a/tests/functional/save02.asm +++ b/tests/functional/save02.asm @@ -45,12 +45,12 @@ __LABEL0: DEFB 74h DEFB 31h #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -58,25 +58,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -85,51 +85,51 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -137,12 +137,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -150,7 +150,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -158,10 +158,10 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -169,25 +169,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -196,39 +196,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -236,57 +236,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -298,27 +298,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -330,7 +330,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -338,15 +338,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -371,14 +371,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -386,25 +386,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -413,30 +413,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -444,75 +444,75 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 33 "save02.bas" #line 1 "save.asm" - + ; Save code "XXX" at address YYY of length ZZZ ; Parameters in the stack are XXX (16 bit) address of string name ; (only first 12 chars will be taken into account) ; YYY and ZZZ are 16 bit on top of the stack. - - - + + + SAVE_CODE: - + PROC - + LOCAL MEMBOT LOCAL SAVE_CONT LOCAL ROM_SAVE LOCAL __ERR_EMPTY LOCAL SAVE_STOP - - ROM_SAVE EQU 0970h + + ROM_SAVE EQU 0970h MEMBOT EQU 23698 ; Use the CALC mem to store header - + pop hl ; Return address pop bc ; data length in bytes pop de ; address start ex (sp), hl ; CALLE => now hl = String - + ; This function will call the ROM SAVE CODE Routine ; Parameters in the stack are HL => String with SAVE name ; (only first 12 chars will be taken into account) ; DE = START address of CODE to save ; BC = Length of data in bytes - + __SAVE_CODE: ; INLINE version ld a, b or c ret z ; Return if block length == 0 - + push ix ld a, h or l jr z, __ERR_EMPTY ; Return if NULL STRING - + ld ix, MEMBOT ld (ix + 00), 3 ; CODE - + ld (ix + 11), c ld (ix + 12), b ; Store long in bytes ld (ix + 13), e ld (ix + 14), d ; Store address in bytes - + push hl ld bc, 9 ld HL, MEMBOT + 1 ld DE, MEMBOT + 2 ld (hl), ' ' ldir ; Fill the filename with blanks - pop hl - + pop hl + ld c, (hl) inc hl ld b, (hl) inc hl ld a, b or c - + __ERR_EMPTY: ld a, ERROR_InvalidFileName jr z, SAVE_STOP ; Return if str len == 0 - + ex de, hl ; Saves HL in DE ld hl, 10 or a @@ -520,27 +520,27 @@ __ERR_EMPTY: ex de, hl jr nc, SAVE_CONT ; Ok BC <= 10 ld bc, 10 ; BC at most 10 chars - + SAVE_CONT: ld de, MEMBOT + 1 ldir ; Copy String block NAME ld l, (ix + 13) - ld h, (ix + 14) ; Restores start of bytes - + ld h, (ix + 14) ; Restores start of bytes + call ROM_SAVE ; Recovers ECHO_E since ROM SAVE changes it ld hl, 1821h ld (23682), hl pop ix ret - + SAVE_STOP: pop ix jp __STOP - + ENDP #line 34 "save02.bas" - + ZXBASIC_USER_DATA: _variableToSave: DEFB 00, 00 diff --git a/tests/functional/save03.asm b/tests/functional/save03.asm index 40baabe36..e417a36e1 100644 --- a/tests/functional/save03.asm +++ b/tests/functional/save03.asm @@ -44,12 +44,12 @@ __LABEL0: DEFB 73h DEFB 74h #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -57,25 +57,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -84,51 +84,51 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -136,12 +136,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -149,7 +149,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -157,10 +157,10 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -168,25 +168,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -195,39 +195,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -235,57 +235,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -297,27 +297,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -329,7 +329,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -337,15 +337,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -370,14 +370,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -385,25 +385,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -412,30 +412,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -443,75 +443,75 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 32 "save03.bas" #line 1 "save.asm" - + ; Save code "XXX" at address YYY of length ZZZ ; Parameters in the stack are XXX (16 bit) address of string name ; (only first 12 chars will be taken into account) ; YYY and ZZZ are 16 bit on top of the stack. - - - + + + SAVE_CODE: - + PROC - + LOCAL MEMBOT LOCAL SAVE_CONT LOCAL ROM_SAVE LOCAL __ERR_EMPTY LOCAL SAVE_STOP - - ROM_SAVE EQU 0970h + + ROM_SAVE EQU 0970h MEMBOT EQU 23698 ; Use the CALC mem to store header - + pop hl ; Return address pop bc ; data length in bytes pop de ; address start ex (sp), hl ; CALLE => now hl = String - + ; This function will call the ROM SAVE CODE Routine ; Parameters in the stack are HL => String with SAVE name ; (only first 12 chars will be taken into account) ; DE = START address of CODE to save ; BC = Length of data in bytes - + __SAVE_CODE: ; INLINE version ld a, b or c ret z ; Return if block length == 0 - + push ix ld a, h or l jr z, __ERR_EMPTY ; Return if NULL STRING - + ld ix, MEMBOT ld (ix + 00), 3 ; CODE - + ld (ix + 11), c ld (ix + 12), b ; Store long in bytes ld (ix + 13), e ld (ix + 14), d ; Store address in bytes - + push hl ld bc, 9 ld HL, MEMBOT + 1 ld DE, MEMBOT + 2 ld (hl), ' ' ldir ; Fill the filename with blanks - pop hl - + pop hl + ld c, (hl) inc hl ld b, (hl) inc hl ld a, b or c - + __ERR_EMPTY: ld a, ERROR_InvalidFileName jr z, SAVE_STOP ; Return if str len == 0 - + ex de, hl ; Saves HL in DE ld hl, 10 or a @@ -519,27 +519,27 @@ __ERR_EMPTY: ex de, hl jr nc, SAVE_CONT ; Ok BC <= 10 ld bc, 10 ; BC at most 10 chars - + SAVE_CONT: ld de, MEMBOT + 1 ldir ; Copy String block NAME ld l, (ix + 13) - ld h, (ix + 14) ; Restores start of bytes - + ld h, (ix + 14) ; Restores start of bytes + call ROM_SAVE ; Recovers ECHO_E since ROM SAVE changes it ld hl, 1821h ld (23682), hl pop ix ret - + SAVE_STOP: pop ix jp __STOP - + ENDP #line 33 "save03.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/sgnf.asm b/tests/functional/sgnf.asm index fc455ba9f..1cba35e7a 100644 --- a/tests/functional/sgnf.asm +++ b/tests/functional/sgnf.asm @@ -32,14 +32,14 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sgnf.asm" - + #line 1 "sgn.asm" - + ; Returns SGN (SIGN) for 32, 16 and 8 bits signed integers, Fixed and FLOAT - + PROC LOCAL __ENDSGN - + __SGNF: or b or c @@ -48,7 +48,7 @@ __SGNF: ret z ld a, e jr __ENDSGN - + __SGNF16: __SGNI32: ld a, h @@ -56,29 +56,29 @@ __SGNI32: or e or d ret z - + ld a, d jr __ENDSGN - + __SGNI16: ld a, h or l ret z ld a, h - + __ENDSGN: or a ld a, 1 ret p neg ret - + ENDP - + #line 2 "sgnf.asm" - + #line 23 "sgnf.bas" - + ZXBASIC_USER_DATA: _y: DEFB 81h diff --git a/tests/functional/sgnf16.asm b/tests/functional/sgnf16.asm index 29691824e..3febd98f9 100644 --- a/tests/functional/sgnf16.asm +++ b/tests/functional/sgnf16.asm @@ -31,14 +31,14 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sgnf16.asm" - + #line 1 "sgn.asm" - + ; Returns SGN (SIGN) for 32, 16 and 8 bits signed integers, Fixed and FLOAT - + PROC LOCAL __ENDSGN - + __SGNF: or b or c @@ -47,7 +47,7 @@ __SGNF: ret z ld a, e jr __ENDSGN - + __SGNF16: __SGNI32: ld a, h @@ -55,29 +55,29 @@ __SGNI32: or e or d ret z - + ld a, d jr __ENDSGN - + __SGNI16: ld a, h or l ret z ld a, h - + __ENDSGN: or a ld a, 1 ret p neg ret - + ENDP - + #line 2 "sgnf16.asm" - + #line 22 "sgnf16.bas" - + ZXBASIC_USER_DATA: _y: DEFB 00h diff --git a/tests/functional/sgni16.asm b/tests/functional/sgni16.asm index 7d8b74fd0..270151ad6 100644 --- a/tests/functional/sgni16.asm +++ b/tests/functional/sgni16.asm @@ -30,14 +30,14 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sgni16.asm" - + #line 1 "sgn.asm" - + ; Returns SGN (SIGN) for 32, 16 and 8 bits signed integers, Fixed and FLOAT - + PROC LOCAL __ENDSGN - + __SGNF: or b or c @@ -46,7 +46,7 @@ __SGNF: ret z ld a, e jr __ENDSGN - + __SGNF16: __SGNI32: ld a, h @@ -54,29 +54,29 @@ __SGNI32: or e or d ret z - + ld a, d jr __ENDSGN - + __SGNI16: ld a, h or l ret z ld a, h - + __ENDSGN: or a ld a, 1 ret p neg ret - + ENDP - + #line 2 "sgni16.asm" - + #line 21 "sgni16.bas" - + ZXBASIC_USER_DATA: _y: DEFB 01h diff --git a/tests/functional/sgni32.asm b/tests/functional/sgni32.asm index 866fc41f6..de9aa29ef 100644 --- a/tests/functional/sgni32.asm +++ b/tests/functional/sgni32.asm @@ -31,14 +31,14 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sgni32.asm" - + #line 1 "sgn.asm" - + ; Returns SGN (SIGN) for 32, 16 and 8 bits signed integers, Fixed and FLOAT - + PROC LOCAL __ENDSGN - + __SGNF: or b or c @@ -47,7 +47,7 @@ __SGNF: ret z ld a, e jr __ENDSGN - + __SGNF16: __SGNI32: ld a, h @@ -55,29 +55,29 @@ __SGNI32: or e or d ret z - + ld a, d jr __ENDSGN - + __SGNI16: ld a, h or l ret z ld a, h - + __ENDSGN: or a ld a, 1 ret p neg ret - + ENDP - + #line 2 "sgni32.asm" - + #line 22 "sgni32.bas" - + ZXBASIC_USER_DATA: _y: DEFB 01h diff --git a/tests/functional/sgni8.asm b/tests/functional/sgni8.asm index 7c9adcfcd..b856942a1 100644 --- a/tests/functional/sgni8.asm +++ b/tests/functional/sgni8.asm @@ -30,9 +30,9 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sgni8.asm" - + ; Returns SGN (SIGN) for 8 bits signed integer - + __SGNI8: or a ret z @@ -40,9 +40,9 @@ __SGNI8: ret p neg ret - + #line 21 "sgni8.bas" - + ZXBASIC_USER_DATA: _y: DEFB 01h diff --git a/tests/functional/sgnu16.asm b/tests/functional/sgnu16.asm index fdefd7421..8ed3e7cb1 100644 --- a/tests/functional/sgnu16.asm +++ b/tests/functional/sgnu16.asm @@ -30,18 +30,18 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sgnu16.asm" - + ; Returns SGN (SIGN) for 16 bits unsigned integer - + __SGNU16: ld a, h or l ret z ld a, 1 ret - + #line 21 "sgnu16.bas" - + ZXBASIC_USER_DATA: _y: DEFB 01h diff --git a/tests/functional/sgnu32.asm b/tests/functional/sgnu32.asm index b14f9ae3d..edb98b2c3 100644 --- a/tests/functional/sgnu32.asm +++ b/tests/functional/sgnu32.asm @@ -31,21 +31,21 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sgnu32.asm" - + ; Returns SGN (SIGN) for 32 bits unsigned integer - + __SGNU32: ld a, h or l or d or e ret z - + ld a, 1 ret - + #line 22 "sgnu32.bas" - + ZXBASIC_USER_DATA: _y: DEFB 01h diff --git a/tests/functional/sgnu8.asm b/tests/functional/sgnu8.asm index 93b606177..069574253 100644 --- a/tests/functional/sgnu8.asm +++ b/tests/functional/sgnu8.asm @@ -30,17 +30,17 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sgnu8.asm" - + ; Returns SGN (SIGN) for 8 bits unsigned integera - + __SGNU8: or a ret z ld a, 1 ret - + #line 21 "sgnu8.bas" - + ZXBASIC_USER_DATA: _y: DEFB 01h diff --git a/tests/functional/shl8.asm b/tests/functional/shl8.asm index ffec09fab..603bdf7c6 100644 --- a/tests/functional/shl8.asm +++ b/tests/functional/shl8.asm @@ -42,7 +42,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/shri8.asm b/tests/functional/shri8.asm index b0b2ac061..b7e6b9411 100644 --- a/tests/functional/shri8.asm +++ b/tests/functional/shri8.asm @@ -42,7 +42,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/shru8.asm b/tests/functional/shru8.asm index 5c9094095..104832de8 100644 --- a/tests/functional/shru8.asm +++ b/tests/functional/shru8.asm @@ -42,7 +42,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/sigilfunc.asm b/tests/functional/sigilfunc.asm index ecbd0367f..96e44d8ac 100644 --- a/tests/functional/sigilfunc.asm +++ b/tests/functional/sigilfunc.asm @@ -46,12 +46,12 @@ _test__leave: __LABEL0: DEFW 0000h #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -59,25 +59,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -86,51 +86,51 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -138,12 +138,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -151,7 +151,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -159,10 +159,10 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -170,25 +170,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -197,39 +197,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -237,57 +237,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -299,27 +299,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -331,7 +331,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -339,15 +339,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -372,14 +372,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -387,25 +387,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -414,30 +414,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -445,19 +445,19 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 34 "sigilfunc.bas" #line 1 "storestr2.asm" - + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication ; HL = address of string memory variable ; DE = address of 2n string. It just copies DE into (HL) ; freeing (HL) previously. - + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -465,25 +465,25 @@ __LOADSTR: ; __FASTCALL__ entry ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -492,38 +492,38 @@ __LOADSTR: ; __FASTCALL__ entry ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -532,57 +532,57 @@ __LOADSTR: ; __FASTCALL__ entry ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -591,47 +591,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -641,43 +641,43 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 9 "storestr2.asm" - + __PISTORE_STR2: ; Indirect store temporary string at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR2: ld c, (hl) ; Dereferences HL inc hl ld h, (hl) ld l, c ; HL = *HL (real string variable address) - + __STORE_STR2: push hl ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = *HL (real string address) - + push de call __MEM_FREE pop de - + pop hl ld (hl), e inc hl ld (hl), d dec hl ; HL points to mem address variable. This might be useful in the future. - + ret - + #line 35 "sigilfunc.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/simple.asm b/tests/functional/simple.asm index a4eb6143d..8622604f1 100644 --- a/tests/functional/simple.asm +++ b/tests/functional/simple.asm @@ -48,17 +48,17 @@ __LABEL0: DEFB 4Ch DEFB 44h #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -66,46 +66,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -118,43 +118,43 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -162,12 +162,12 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -175,51 +175,51 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "in_screen.asm" - + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -228,17 +228,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -246,26 +246,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -279,45 +279,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -328,28 +328,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -357,28 +357,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -387,83 +387,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -472,32 +472,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -507,7 +507,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -515,20 +515,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -538,7 +538,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -549,19 +549,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -571,7 +571,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -582,19 +582,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -604,7 +604,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -617,22 +617,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -641,79 +641,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -722,75 +722,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -800,7 +800,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -812,16 +812,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -835,49 +835,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -888,17 +888,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -911,27 +911,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -939,10 +939,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -959,80 +959,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1049,8 +1049,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1074,17 +1074,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1095,7 +1095,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1105,21 +1105,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1138,9 +1138,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1165,21 +1165,21 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 35 "simple.bas" #line 1 "printstr.asm" - - - - + + + + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1187,25 +1187,25 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1214,41 +1214,41 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1256,25 +1256,25 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1283,39 +1283,39 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -1323,56 +1323,56 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -1381,57 +1381,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -1440,47 +1440,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -1490,51 +1490,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 5 "printstr.asm" - + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1543,11 +1543,11 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 36 "simple.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/slice0.asm b/tests/functional/slice0.asm index 005b88490..17f562f34 100644 --- a/tests/functional/slice0.asm +++ b/tests/functional/slice0.asm @@ -41,19 +41,19 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "storestr2.asm" - + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication ; HL = address of string memory variable ; DE = address of 2n string. It just copies DE into (HL) ; freeing (HL) previously. - + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -61,25 +61,25 @@ __CALL_BACK__: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -88,41 +88,41 @@ __CALL_BACK__: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -130,25 +130,25 @@ __CALL_BACK__: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -157,39 +157,39 @@ __CALL_BACK__: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -197,56 +197,56 @@ __CALL_BACK__: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -255,57 +255,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -314,47 +314,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -364,84 +364,84 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 9 "storestr2.asm" - + __PISTORE_STR2: ; Indirect store temporary string at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR2: ld c, (hl) ; Dereferences HL inc hl ld h, (hl) ld l, c ; HL = *HL (real string variable address) - + __STORE_STR2: push hl ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = *HL (real string address) - + push de call __MEM_FREE pop de - + pop hl ld (hl), e inc hl ld (hl), d dec hl ; HL points to mem address variable. This might be useful in the future. - + ret - + #line 29 "slice0.bas" #line 1 "strslice.asm" - + ; String slicing library ; HL = Str pointer ; DE = String start ; BC = String character end ; A register => 0 => the HL pointer wont' be freed from the HEAP ; e.g. a$(5 TO 10) => HL = a$; DE = 5; BC = 10 - - ; This implements a$(X to Y) being X and Y first and + + ; This implements a$(X to Y) being X and Y first and ; last characters respectively. If X > Y, NULL is returned - + ; Otherwise returns a pointer to a$ FROM X to Y (starting from 0) ; if Y > len(a$), then a$ will be padded with spaces (reallocating - ; it in dynamic memory if needed). Returns pointer (HL) to resulting + ; it in dynamic memory if needed). Returns pointer (HL) to resulting ; string. NULL (0) if no memory for padding. ; - + #line 1 "strlen.asm" - + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL - + __STRLEN: ; Direct FASTCALL entry ld a, h or l ret z - + ld a, (hl) inc hl ld h, (hl) ; LEN(str) in HL ld l, a ret - - + + #line 18 "strslice.asm" #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -449,25 +449,25 @@ __STRLEN: ; Direct FASTCALL entry ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -476,51 +476,51 @@ __STRLEN: ; Direct FASTCALL entry ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -528,12 +528,12 @@ __STRLEN: ; Direct FASTCALL entry ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -541,16 +541,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -562,27 +562,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -594,7 +594,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -602,15 +602,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -635,14 +635,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -650,41 +650,41 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 19 "strslice.asm" - - + + __STRSLICE: ; Callee entry pop hl ; Return ADDRESS pop bc ; Last char pos pop de ; 1st char pos ex (sp), hl ; CALLEE. -> String start - + __STRSLICE_FAST: ; __FASTCALL__ Entry PROC - + LOCAL __CONT LOCAL __EMPTY LOCAL __FREE_ON_EXIT - + push hl ; Stores original HL pointer to be recovered on exit ex af, af' ; Saves A register for later - + push hl call __STRLEN - inc bc ; Last character position + 1 (string starts from 0) + inc bc ; Last character position + 1 (string starts from 0) or a sbc hl, bc ; Compares length with last char position jr nc, __CONT ; If Carry => We must copy to end of string @@ -692,19 +692,19 @@ __STRSLICE_FAST: ; __FASTCALL__ Entry ld b, h ld c, l ; Copy to the end of str ccf ; Clears Carry flag for next subtraction - + __CONT: - ld h, b + ld h, b ld l, c ; HL = Last char position to copy (1 for char 0, 2 for char 1, etc) sbc hl, de ; HL = LEN(a$) - DE => Number of chars to copy jr z, __EMPTY ; 0 Chars to copy => Return HL = 0 (NULL STR) jr c, __EMPTY ; If Carry => Nothing to return (NULL STR) - + ld b, h ld c, l ; BC = Number of chars to copy inc bc inc bc ; +2 bytes for string length number - + push bc push de call __MEM_ALLOC @@ -713,15 +713,15 @@ __CONT: ld a, h or l jr z, __EMPTY ; Return if NULL (no memory) - + dec bc dec bc ; Number of chars to copy (Len of slice) - + ld (hl), c inc hl ld (hl), b inc hl ; Stores new string length - + ex (sp), hl ; Pointer to A$ now in HL; Pointer to new string chars in Stack inc hl inc hl ; Skip string length @@ -734,26 +734,26 @@ __CONT: dec de ; Points to String LEN start ex de, hl ; Returns it in HL jr __FREE_ON_EXIT - + __EMPTY: ; Return NULL (empty) string pop hl ld hl, 0 ; Return NULL - - + + __FREE_ON_EXIT: ex af, af' ; Recover original A register ex (sp), hl ; Original HL pointer - + or a call nz, __MEM_FREE - + pop hl ; Recover result - ret - - ENDP - + ret + + ENDP + #line 30 "slice0.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/slice2.asm b/tests/functional/slice2.asm index 8d3da9761..d9ecf30c7 100644 --- a/tests/functional/slice2.asm +++ b/tests/functional/slice2.asm @@ -125,20 +125,20 @@ __LABEL0: DEFB 6Ch DEFB 64h #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -146,36 +146,36 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 9 "cls.asm" - + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -188,40 +188,40 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 113 "slice2.bas" #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -229,12 +229,12 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -242,7 +242,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -250,10 +250,10 @@ __STOP: ret #line 114 "slice2.bas" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -261,25 +261,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -288,41 +288,41 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -330,25 +330,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -357,39 +357,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -397,56 +397,56 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -455,57 +455,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -514,47 +514,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -564,17 +564,17 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 115 "slice2.bas" #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -582,25 +582,25 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -609,40 +609,40 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - - + + + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -654,27 +654,27 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -686,7 +686,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -694,15 +694,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -727,14 +727,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -742,25 +742,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -769,30 +769,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -800,124 +800,124 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 116 "slice2.bas" #line 1 "pstorestr2.asm" - + ; vim:ts=4:et:sw=4 - ; + ; ; Stores an string (pointer to the HEAP by DE) into the address pointed ; by (IX + BC). No new copy of the string is created into the HEAP, since ; it's supposed it's already created (temporary string) ; - + #line 1 "storestr2.asm" - + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication ; HL = address of string memory variable ; DE = address of 2n string. It just copies DE into (HL) ; freeing (HL) previously. - - - + + + __PISTORE_STR2: ; Indirect store temporary string at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR2: ld c, (hl) ; Dereferences HL inc hl ld h, (hl) ld l, c ; HL = *HL (real string variable address) - + __STORE_STR2: push hl ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = *HL (real string address) - + push de call __MEM_FREE pop de - + pop hl ld (hl), e inc hl ld (hl), d dec hl ; HL points to mem address variable. This might be useful in the future. - + ret - + #line 9 "pstorestr2.asm" - + __PSTORE_STR2: push ix pop hl add hl, bc jp __STORE_STR2 - + #line 117 "slice2.bas" #line 1 "strlen.asm" - + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL - + __STRLEN: ; Direct FASTCALL entry ld a, h or l ret z - + ld a, (hl) inc hl ld h, (hl) ; LEN(str) in HL ld l, a ret - - + + #line 118 "slice2.bas" #line 1 "strslice.asm" - + ; String slicing library ; HL = Str pointer ; DE = String start ; BC = String character end ; A register => 0 => the HL pointer wont' be freed from the HEAP ; e.g. a$(5 TO 10) => HL = a$; DE = 5; BC = 10 - - ; This implements a$(X to Y) being X and Y first and + + ; This implements a$(X to Y) being X and Y first and ; last characters respectively. If X > Y, NULL is returned - + ; Otherwise returns a pointer to a$ FROM X to Y (starting from 0) ; if Y > len(a$), then a$ will be padded with spaces (reallocating - ; it in dynamic memory if needed). Returns pointer (HL) to resulting + ; it in dynamic memory if needed). Returns pointer (HL) to resulting ; string. NULL (0) if no memory for padding. ; - - - - - + + + + + __STRSLICE: ; Callee entry pop hl ; Return ADDRESS pop bc ; Last char pos pop de ; 1st char pos ex (sp), hl ; CALLEE. -> String start - + __STRSLICE_FAST: ; __FASTCALL__ Entry PROC - + LOCAL __CONT LOCAL __EMPTY LOCAL __FREE_ON_EXIT - + push hl ; Stores original HL pointer to be recovered on exit ex af, af' ; Saves A register for later - + push hl call __STRLEN - inc bc ; Last character position + 1 (string starts from 0) + inc bc ; Last character position + 1 (string starts from 0) or a sbc hl, bc ; Compares length with last char position jr nc, __CONT ; If Carry => We must copy to end of string @@ -925,19 +925,19 @@ __STRSLICE_FAST: ; __FASTCALL__ Entry ld b, h ld c, l ; Copy to the end of str ccf ; Clears Carry flag for next subtraction - + __CONT: - ld h, b + ld h, b ld l, c ; HL = Last char position to copy (1 for char 0, 2 for char 1, etc) sbc hl, de ; HL = LEN(a$) - DE => Number of chars to copy jr z, __EMPTY ; 0 Chars to copy => Return HL = 0 (NULL STR) jr c, __EMPTY ; If Carry => Nothing to return (NULL STR) - + ld b, h ld c, l ; BC = Number of chars to copy inc bc inc bc ; +2 bytes for string length number - + push bc push de call __MEM_ALLOC @@ -946,15 +946,15 @@ __CONT: ld a, h or l jr z, __EMPTY ; Return if NULL (no memory) - + dec bc dec bc ; Number of chars to copy (Len of slice) - + ld (hl), c inc hl ld (hl), b inc hl ; Stores new string length - + ex (sp), hl ; Pointer to A$ now in HL; Pointer to new string chars in Stack inc hl inc hl ; Skip string length @@ -967,26 +967,26 @@ __CONT: dec de ; Points to String LEN start ex de, hl ; Returns it in HL jr __FREE_ON_EXIT - + __EMPTY: ; Return NULL (empty) string pop hl ld hl, 0 ; Return NULL - - + + __FREE_ON_EXIT: ex af, af' ; Recover original A register ex (sp), hl ; Original HL pointer - + or a call nz, __MEM_FREE - + pop hl ; Recover result - ret - - ENDP - + ret + + ENDP + #line 119 "slice2.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/spfill.asm b/tests/functional/spfill.asm index 0a8e6dddb..fb3030fdc 100644 --- a/tests/functional/spfill.asm +++ b/tests/functional/spfill.asm @@ -481,25 +481,25 @@ __LABEL0: DEFW 0001h DEFB 61h #line 1 "circle.asm" - + ; Bresenham's like circle algorithm ; best known as Middle Point Circle drawing algorithm - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -507,12 +507,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -520,7 +520,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -528,22 +528,22 @@ __STOP: ret #line 5 "circle.asm" #line 1 "plot.asm" - + ; MIXED __FASTCAL__ / __CALLE__ PLOT Function ; Plots a point into the screen calling the ZX ROM PLOT routine - + ; Y in A (accumulator) ; X in top of the stack - - + + #line 1 "in_screen.asm" - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -551,75 +551,75 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 2 "in_screen.asm" - - + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 9 "plot.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -632,48 +632,48 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 10 "plot.asm" - + PLOT: PROC - + LOCAL PLOT_SUB LOCAL PIXEL_ADDR LOCAL COORDS LOCAL __PLOT_ERR LOCAL P_FLAG LOCAL __PLOT_OVER1 - + P_FLAG EQU 23697 - + pop hl ex (sp), hl ; Callee - + ld b, a - ld c, h - + ld c, h + ld a, 191 cp b jr c, __PLOT_ERR ; jr is faster here (#1) - + __PLOT: ; __FASTCALL__ entry (b, c) = pixel coords (y, x) ld (COORDS), bc ; Saves current point ld a, 191 ; Max y coord @@ -681,7 +681,7 @@ __PLOT: ; __FASTCALL__ entry (b, c) = pixel coords (y, x) res 6, h ; Starts from 0 ld bc, (SCREEN_ADDR) add hl, bc ; Now current offset - + ld b, a inc b ld a, 0FEh @@ -689,7 +689,7 @@ __PLOT: ; __FASTCALL__ entry (b, c) = pixel coords (y, x) __PLOT_LOOP: rrca djnz __PLOT_LOOP - + ld b, a ld a, (P_FLAG) ld c, a @@ -697,18 +697,18 @@ __PLOT_LOOP: bit 0, c ; is it OVER 1 jr nz, __PLOT_OVER1 and b - + __PLOT_OVER1: bit 2, c ; is it inverse 1 jr nz, __PLOT_END - + xor b cpl - + LOCAL __PLOT_END __PLOT_END: ld (hl), a - + ;; gets ATTR position with offset given in SCREEN_ADDR ld a, h rrca @@ -719,36 +719,36 @@ __PLOT_END: ld h, a ld de, (SCREEN_ADDR) add hl, de ;; Final screen addr - + LOCAL PO_ATTR_2 PO_ATTR_2 EQU 0BE4h ; Another entry to PO_ATTR jp PO_ATTR_2 ; This will update attr accordingly. Beware, uses IY - + __PLOT_ERR: jp __OUT_OF_SCREEN_ERR ; Spent 3 bytes, but saves 3 T-States at (#1) - + PLOT_SUB EQU 22ECh - PIXEL_ADDR EQU 22ACh + PIXEL_ADDR EQU 22ACh COORDS EQU 5C7Dh ENDP #line 6 "circle.asm" - - + + ; Draws a circle at X, Y of radius R ; X, Y on the Stack, R in accumulator (Byte) - + PROC LOCAL __CIRCLE_ERROR LOCAL __CIRCLE_LOOP LOCAL __CIRCLE_NEXT - + __CIRCLE_ERROR: jp __OUT_OF_SCREEN_ERR ;; __CIRCLE_ERROR EQU __OUT_OF_SCREEN_ERR ;; __CIRCLE_ERROR: ;; ; Jumps here if out of screen ;; scf ; Always sets carry Flag - ;; + ;; ;; ld a, ERROR_OutOfScreen ;; ld (ERR_NR), a ;; ret @@ -758,95 +758,95 @@ CIRCLE: pop de ; D = Y ex (sp), hl ; __CALLEE__ convention ld e, h ; E = X - - - ld h, a ; H = R + + + ld h, a ; H = R add a, d sub 192 jr nc, __CIRCLE_ERROR - + ld a, d sub h jr c, __CIRCLE_ERROR - + ld a, e sub h jr c, __CIRCLE_ERROR - + ld a, h add a, e jr c, __CIRCLE_ERROR - - + + ; __FASTCALL__ Entry: D, E = Y, X point of the center ; A = Radious __CIRCLE: - push de + push de ld a, h exx pop de ; D'E' = x0, y0 ld h, a ; H' = r - + ld c, e ld a, h add a, d ld b, a call __CIRCLE_PLOT ; PLOT (x0, y0 + r) - + ld b, d ld a, h add a, e ld c, a call __CIRCLE_PLOT ; PLOT (x0 + r, y0) - + ld c, e ld a, d sub h ld b, a call __CIRCLE_PLOT ; PLOT (x0, y0 - r) - + ld b, d ld a, e sub h ld c, a call __CIRCLE_PLOT ; PLOT (x0 - r, y0) - + exx ld b, 0 ; B = x = 0 ld c, h ; C = y = Radius ld hl, 1 or a sbc hl, bc ; HL = f = 1 - radius - + ex de, hl ld hl, 0 or a sbc hl, bc ; HL = -radius add hl, hl ; HL = -2 * radius ex de, hl ; DE = -2 * radius = ddF_y, HL = f - + xor a ; A = ddF_x = 0 ex af, af' ; Saves it - + __CIRCLE_LOOP: ld a, b cp c ret nc ; Returns when x >= y - + bit 7, h ; HL >= 0? : if (f >= 0)... jp nz, __CIRCLE_NEXT - + dec c ; y-- inc de inc de ; ddF_y += 2 - + add hl, de ; f += ddF_y - + __CIRCLE_NEXT: inc b ; x++ ex af, af' add a, 2 ; 1 Cycle faster than inc a, inc a - + inc hl ; f++ push af add a, l @@ -856,11 +856,11 @@ __CIRCLE_NEXT: ld h, a pop af ex af, af' - - push bc + + push bc exx pop hl ; H'L' = Y, X - + ld a, d add a, h ld b, a ; B = y0 + y @@ -868,7 +868,7 @@ __CIRCLE_NEXT: add a, l ld c, a ; C = x0 + x call __CIRCLE_PLOT ; plot(x0 + x, y0 + y) - + ld a, d add a, h ld b, a ; B = y0 + y @@ -876,7 +876,7 @@ __CIRCLE_NEXT: sub l ld c, a ; C = x0 - x call __CIRCLE_PLOT ; plot(x0 - x, y0 + y) - + ld a, d sub h ld b, a ; B = y0 - y @@ -884,7 +884,7 @@ __CIRCLE_NEXT: add a, l ld c, a ; C = x0 + x call __CIRCLE_PLOT ; plot(x0 + x, y0 - y) - + ld a, d sub h ld b, a ; B = y0 - y @@ -892,79 +892,79 @@ __CIRCLE_NEXT: sub l ld c, a ; C = x0 - x call __CIRCLE_PLOT ; plot(x0 - x, y0 - y) - + ld a, d add a, l ld b, a ; B = y0 + x - ld a, e + ld a, e add a, h ld c, a ; C = x0 + y call __CIRCLE_PLOT ; plot(x0 + y, y0 + x) - + ld a, d add a, l ld b, a ; B = y0 + x - ld a, e + ld a, e sub h ld c, a ; C = x0 - y call __CIRCLE_PLOT ; plot(x0 - y, y0 + x) - + ld a, d sub l ld b, a ; B = y0 - x - ld a, e + ld a, e add a, h ld c, a ; C = x0 + y call __CIRCLE_PLOT ; plot(x0 + y, y0 - x) - + ld a, d sub l ld b, a ; B = y0 - x - ld a, e + ld a, e sub h ld c, a ; C = x0 + y call __CIRCLE_PLOT ; plot(x0 - y, y0 - x) - + exx jp __CIRCLE_LOOP - - - + + + __CIRCLE_PLOT: ; Plots a point of the circle, preserving HL and DE push hl push de - call __PLOT + call __PLOT pop de pop hl ret - + ENDP #line 469 "spfill.bas" - + #line 1 "pause.asm" - + ; The PAUSE statement (Calling the ROM) - + __PAUSE: ld b, h ld c, l jp 1F3Dh ; PAUSE_1 #line 471 "spfill.bas" #line 1 "usr_str.asm" - + ; This function just returns the address of the UDG of the given str. ; If the str is EMPTY or not a letter, 0 is returned and ERR_NR set ; to "A: Invalid Argument" - + ; On entry HL points to the string ; and A register is non-zero if the string must be freed (TMP string) - - + + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -972,13 +972,13 @@ __PAUSE: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 10 "usr_str.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -986,25 +986,25 @@ __PAUSE: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1013,41 +1013,41 @@ __PAUSE: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1055,25 +1055,25 @@ __PAUSE: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1082,39 +1082,39 @@ __PAUSE: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -1122,56 +1122,56 @@ __PAUSE: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -1180,57 +1180,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -1239,47 +1239,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -1289,27 +1289,27 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 11 "usr_str.asm" - + USR_STR: ex af, af' ; Saves A flag - + ld a, h or l jr z, USR_ERROR ; a$ = NULL => Invalid Arg - + ld d, h ; Saves HL in DE, for ld e, l ; later usage - + ld c, (hl) inc hl ld a, (hl) or c jr z, USR_ERROR ; a$ = "" => Invalid Arg - + inc hl ld a, (hl) ; Only the 1st char is needed and 11011111b ; Convert it to UPPER CASE @@ -1321,31 +1321,31 @@ USR_STR: add hl, hl ; hl = A * 8 ld bc, (UDG) add hl, bc - + ;; Now checks if the string must be released ex af, af' ; Recovers A flag or a ret z ; return if not - + push hl ; saves result since __MEM_FREE changes HL ex de, hl ; Recovers original HL value call __MEM_FREE pop hl ret - + USR_ERROR: ex de, hl ; Recovers original HL value ex af, af' ; Recovers A flag or a call nz, __MEM_FREE - + ld a, ERROR_InvalidArg ld (ERR_NR), a ld hl, 0 ret - + #line 472 "spfill.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/stoperr.asm b/tests/functional/stoperr.asm index 0ded9c6ad..2be76523c 100644 --- a/tests/functional/stoperr.asm +++ b/tests/functional/stoperr.asm @@ -35,20 +35,20 @@ __CALL_BACK__: ld c, l jp __END_PROGRAM #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -56,12 +56,12 @@ __CALL_BACK__: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -69,14 +69,14 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 26 "stoperr.bas" - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/storecstr.asm b/tests/functional/storecstr.asm index fb2d2fcd5..a613f3512 100644 --- a/tests/functional/storecstr.asm +++ b/tests/functional/storecstr.asm @@ -40,7 +40,7 @@ __LABEL0: DEFB 6Ch DEFB 6Fh #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -51,15 +51,15 @@ __LABEL0: ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -67,25 +67,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -94,52 +94,52 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -147,12 +147,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -160,7 +160,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -168,10 +168,10 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -179,25 +179,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -206,42 +206,42 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -249,25 +249,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -276,39 +276,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -316,57 +316,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -378,27 +378,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -410,7 +410,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -418,15 +418,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -451,14 +451,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -466,25 +466,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 71 "realloc.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -492,25 +492,25 @@ __MEM_SUBTRACT: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -519,38 +519,38 @@ __MEM_SUBTRACT: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -559,57 +559,57 @@ __MEM_SUBTRACT: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -618,47 +618,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -668,12 +668,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 72 "realloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -692,29 +692,29 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -723,111 +723,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -843,7 +843,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -851,44 +851,44 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 28 "storecstr.bas" - + ZXBASIC_USER_DATA: _f: DEFB 00, 00 diff --git a/tests/functional/storef.asm b/tests/functional/storef.asm index cc15fd86c..0d2aa1e79 100644 --- a/tests/functional/storef.asm +++ b/tests/functional/storef.asm @@ -32,7 +32,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "storef.asm" - + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -40,7 +40,7 @@ __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory pop hl ; HL <- IX add hl, de ; HL <- IX + HL pop de - + __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register ex af, af' ld a, (hl) @@ -48,7 +48,7 @@ __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address ld h, (hl) ld l, a ; HL = (HL) ex af, af' - + __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), a inc hl @@ -60,9 +60,9 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL inc hl ld (hl), b ret - + #line 23 "storef.bas" - + ZXBASIC_USER_DATA: _f: DEFB 00, 00, 00, 00, 00 diff --git a/tests/functional/storestr0.asm b/tests/functional/storestr0.asm index f7e4eafd0..d776ba06b 100644 --- a/tests/functional/storestr0.asm +++ b/tests/functional/storestr0.asm @@ -33,7 +33,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -44,15 +44,15 @@ __CALL_BACK__: ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -60,25 +60,25 @@ __CALL_BACK__: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -87,52 +87,52 @@ __CALL_BACK__: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -140,12 +140,12 @@ __CALL_BACK__: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -153,7 +153,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -161,10 +161,10 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -172,25 +172,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -199,42 +199,42 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -242,25 +242,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -269,39 +269,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -309,57 +309,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -371,27 +371,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -403,7 +403,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -411,15 +411,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -444,14 +444,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -459,25 +459,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 71 "realloc.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -485,25 +485,25 @@ __MEM_SUBTRACT: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -512,38 +512,38 @@ __MEM_SUBTRACT: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -552,57 +552,57 @@ __MEM_SUBTRACT: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -611,47 +611,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -661,12 +661,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 72 "realloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -685,29 +685,29 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -716,111 +716,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -836,7 +836,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -844,44 +844,44 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 21 "storestr0.bas" - + ZXBASIC_USER_DATA: _f: DEFB 00, 00 diff --git a/tests/functional/storestr1.asm b/tests/functional/storestr1.asm index 4f4a0225e..f49371653 100644 --- a/tests/functional/storestr1.asm +++ b/tests/functional/storestr1.asm @@ -70,10 +70,10 @@ __LABEL0: DEFB 6Ch DEFB 6Fh #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -81,25 +81,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -108,41 +108,41 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -150,25 +150,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -177,39 +177,39 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -217,56 +217,56 @@ __LABEL0: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -275,57 +275,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -334,47 +334,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -384,20 +384,20 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 58 "storestr1.bas" #line 1 "pstorestr.asm" - + ; vim:ts=4:et:sw=4 - ; + ; ; Stores an string (pointer to the HEAP by DE) into the address pointed ; by (IX + BC). A new copy of the string is created into the HEAP ; - + #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -408,15 +408,15 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -424,25 +424,25 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -451,52 +451,52 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -504,12 +504,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -517,7 +517,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -525,10 +525,10 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -536,25 +536,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -563,40 +563,40 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - - + + + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -608,27 +608,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -640,7 +640,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -648,15 +648,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -681,14 +681,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -696,23 +696,23 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 71 "realloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -731,29 +731,29 @@ __MEM_SUBTRACT: ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -762,111 +762,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -882,7 +882,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -890,52 +890,52 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 8 "pstorestr.asm" - + __PSTORE_STR: push ix pop hl add hl, bc jp __STORE_STR - + #line 59 "storestr1.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/storestr2.asm b/tests/functional/storestr2.asm index 3b363c622..fffb1fd45 100644 --- a/tests/functional/storestr2.asm +++ b/tests/functional/storestr2.asm @@ -76,10 +76,10 @@ __LABEL0: DEFB 6Ch DEFB 6Fh #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -87,25 +87,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -114,41 +114,41 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -156,25 +156,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -183,39 +183,39 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -223,56 +223,56 @@ __LABEL0: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -281,57 +281,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -340,47 +340,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -390,17 +390,17 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 64 "storestr2.bas" #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -408,25 +408,25 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -435,51 +435,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -487,12 +487,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -500,16 +500,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -521,27 +521,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -553,7 +553,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -561,15 +561,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -594,14 +594,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -609,25 +609,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -636,30 +636,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -667,15 +667,15 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 65 "storestr2.bas" #line 1 "pstorestr.asm" - + ; vim:ts=4:et:sw=4 - ; + ; ; Stores an string (pointer to the HEAP by DE) into the address pointed ; by (IX + BC). A new copy of the string is created into the HEAP ; - + #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -686,15 +686,15 @@ __LOADSTR: ; __FASTCALL__ entry ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -702,25 +702,25 @@ __LOADSTR: ; __FASTCALL__ entry ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -729,42 +729,42 @@ __LOADSTR: ; __FASTCALL__ entry ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - - - - + + + + + + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -783,29 +783,29 @@ __LOADSTR: ; __FASTCALL__ entry ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -814,111 +814,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -934,7 +934,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -942,52 +942,52 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 8 "pstorestr.asm" - + __PSTORE_STR: push ix pop hl add hl, bc jp __STORE_STR - + #line 66 "storestr2.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/storeu16.asm b/tests/functional/storeu16.asm index 13d8ae3b2..4e5ac9007 100644 --- a/tests/functional/storeu16.asm +++ b/tests/functional/storeu16.asm @@ -28,7 +28,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _f: DEFB 00, 00 diff --git a/tests/functional/storeu32.asm b/tests/functional/storeu32.asm index 25ae9049e..b753e7d0f 100644 --- a/tests/functional/storeu32.asm +++ b/tests/functional/storeu32.asm @@ -30,7 +30,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _f: DEFB 00, 00, 00, 00 diff --git a/tests/functional/storeu8.asm b/tests/functional/storeu8.asm index fade56588..a30427b39 100644 --- a/tests/functional/storeu8.asm +++ b/tests/functional/storeu8.asm @@ -28,7 +28,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _f: DEFB 00 diff --git a/tests/functional/str0.asm b/tests/functional/str0.asm index 55138ad61..5468ee6c1 100644 --- a/tests/functional/str0.asm +++ b/tests/functional/str0.asm @@ -72,10 +72,10 @@ __LABEL0: DEFW 0001h DEFB 31h #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -83,25 +83,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -110,41 +110,41 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -152,25 +152,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -179,39 +179,39 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -219,56 +219,56 @@ __LABEL0: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -277,57 +277,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -336,47 +336,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -386,27 +386,27 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 59 "str0.bas" #line 1 "print_eol_attr.asm" - + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes - + #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -414,46 +414,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -466,43 +466,43 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -510,12 +510,12 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -523,51 +523,51 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "in_screen.asm" - + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -576,17 +576,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -594,26 +594,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -627,45 +627,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -676,28 +676,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -705,28 +705,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -735,83 +735,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -820,32 +820,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -855,7 +855,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -863,20 +863,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -886,7 +886,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -897,19 +897,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -919,7 +919,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -930,19 +930,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -952,7 +952,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -965,22 +965,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -989,79 +989,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -1070,75 +1070,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -1148,7 +1148,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -1160,16 +1160,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1183,49 +1183,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1236,17 +1236,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1259,27 +1259,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1287,10 +1287,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1307,80 +1307,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1397,8 +1397,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1422,17 +1422,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1443,7 +1443,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1453,21 +1453,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1486,9 +1486,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1513,64 +1513,64 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 5 "print_eol_attr.asm" - - + + PRINT_EOL_ATTR: call PRINT_EOL jp COPY_ATTR #line 60 "str0.bas" #line 1 "printstr.asm" - - - - - - + + + + + + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1579,23 +1579,23 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 61 "str0.bas" #line 1 "str.asm" - + ; The STR$( ) BASIC function implementation - + ; Given a FP number in C ED LH ; Returns a pointer (in HL) to the memory heap ; containing the FP number string representation - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1603,25 +1603,25 @@ __PRINT_STR: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1630,40 +1630,40 @@ __PRINT_STR: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - - + + + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -1675,27 +1675,27 @@ __PRINT_STR: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -1707,7 +1707,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -1715,15 +1715,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -1748,14 +1748,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -1763,53 +1763,53 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 8 "str.asm" #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -1825,173 +1825,173 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 9 "str.asm" - - + + __STR: - + __STR_FAST: - + PROC LOCAL __STR_END LOCAL RECLAIM2 LOCAL STK_END - + ld hl, (STK_END) push hl; Stores STK_END ld hl, (ATTR_T) ; Saves ATTR_T since it's changed by STR$ due to a ROM BUG push hl - + call __FPSTACK_PUSH ; Push number into stack rst 28h ; # Rom Calculator defb 2Eh ; # STR$(x) defb 38h ; # END CALC call __FPSTACK_POP ; Recovers string parameters to A ED CB (Only ED LH are important) - + pop hl ld (ATTR_T), hl ; Restores ATTR_T pop hl ld (STK_END), hl ; Balance STK_END to avoid STR$ bug - + push bc push de - + inc bc inc bc call __MEM_ALLOC ; HL Points to new block - + pop de pop bc - + push hl ld a, h or l jr z, __STR_END ; Return if NO MEMORY (NULL) - + push bc push de - ld (hl), c + ld (hl), c inc hl ld (hl), b inc hl ; Copies length - + ex de, hl ; HL = start of original string ldir ; Copies string content - + pop de ; Original (ROM-CALC) string pop bc ; Original Length - + __STR_END: ex de, hl inc bc - + call RECLAIM2 ; Frees TMP Memory pop hl ; String result - + ret - + RECLAIM2 EQU 19E8h STK_END EQU 5C65h - + ENDP - + #line 62 "str0.bas" #line 1 "strcat.asm" - - + + #line 1 "strlen.asm" - + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL - + __STRLEN: ; Direct FASTCALL entry ld a, h or l ret z - + ld a, (hl) inc hl ld h, (hl) ; LEN(str) in HL ld l, a ret - - + + #line 3 "strcat.asm" - + __ADDSTR: ; Implements c$ = a$ + b$ ; hl = &a$, de = &b$ (pointers) - - + + __STRCAT2: ; This routine creates a new string in dynamic space ; making room for it. Then copies a$ + b$ into it. ; HL = a$, DE = b$ - + PROC - + LOCAL __STR_CONT LOCAL __STRCATEND - + push hl call __STRLEN ld c, l ld b, h ; BC = LEN(a$) ex (sp), hl ; (SP) = LEN (a$), HL = a$ push hl ; Saves pointer to a$ - + inc bc inc bc ; +2 bytes to store length - + ex de, hl push hl call __STRLEN ; HL = len(b$) - + add hl, bc ; Total str length => 2 + len(a$) + len(b$) - + ld c, l ld b, h ; BC = Total str length + 2 - call __MEM_ALLOC - pop de ; HL = c$, DE = b$ - + call __MEM_ALLOC + pop de ; HL = c$, DE = b$ + ex de, hl ; HL = b$, DE = c$ - ex (sp), hl ; HL = a$, (SP) = b$ - + ex (sp), hl ; HL = a$, (SP) = b$ + exx - pop de ; D'E' = b$ + pop de ; D'E' = b$ exx - + pop bc ; LEN(a$) - + ld a, d or e ret z ; If no memory: RETURN - + __STR_CONT: push de ; Address of c$ - + ld a, h or l jr nz, __STR_CONT1 ; If len(a$) != 0 do copy - + ; a$ is NULL => uses HL = DE for transfer ld h, d ld l, e ld (hl), a ; This will copy 00 00 at (DE) location - inc de ; + inc de ; dec bc ; Ensure BC will be set to 1 in the next step - + __STR_CONT1: ; Copies a$ (HL) into c$ (DE) - inc bc + inc bc inc bc ; BC = BC + 2 ldir ; MEMCOPY: c$ = a$ pop hl ; HL = c$ - + exx push de ; Recovers b$; A ex hl,hl' would be very handy exx - - pop de ; DE = b$ - + + pop de ; DE = b$ + __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ; NOTE: Both DE, BC and AF are modified and lost ; Returns HL (pointer to a$) @@ -1999,83 +1999,83 @@ __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ld a, d or e ret z ; Returns if de is NULL (nothing to copy) - + push hl ; Saves HL to return it later - + ld c, (hl) inc hl ld b, (hl) inc hl add hl, bc ; HL = end of (a$) string ; bc = len(a$) push bc ; Saves LEN(a$) for later - + ex de, hl ; DE = end of string (Begin of copy addr) ld c, (hl) inc hl ld b, (hl) ; BC = len(b$) - + ld a, b or c jr z, __STRCATEND; Return if len(b$) == 0 - + push bc ; Save LEN(b$) inc hl ; Skip 2nd byte of len(b$) ldir ; Concatenate b$ - + pop bc ; Recovers length (b$) pop hl ; Recovers length (a$) add hl, bc ; HL = LEN(a$) + LEN(b$) = LEN(a$+b$) ex de, hl ; DE = LEN(a$+b$) pop hl - + ld (hl), e ; Updates new LEN and return inc hl ld (hl), d dec hl ret - + __STRCATEND: pop hl ; Removes Len(a$) pop hl ; Restores original HL, so HL = a$ ret - + ENDP - + #line 63 "str0.bas" #line 1 "u32tofreg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "u32tofreg.asm" __I8TOFREG: ld l, a @@ -2084,35 +2084,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -2120,20 +2120,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -2141,32 +2141,32 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 64 "str0.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/str00.asm b/tests/functional/str00.asm index 68f7b4c78..6b66923b0 100644 --- a/tests/functional/str00.asm +++ b/tests/functional/str00.asm @@ -37,7 +37,7 @@ __LABEL0: DEFB 35h DEFB 32h #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -48,15 +48,15 @@ __LABEL0: ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -64,25 +64,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -91,52 +91,52 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -144,12 +144,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -157,7 +157,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -165,10 +165,10 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -176,25 +176,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -203,42 +203,42 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -246,25 +246,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -273,39 +273,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -313,57 +313,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -375,27 +375,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -407,7 +407,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -415,15 +415,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -448,14 +448,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -463,25 +463,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 71 "realloc.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -489,25 +489,25 @@ __MEM_SUBTRACT: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -516,38 +516,38 @@ __MEM_SUBTRACT: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -556,57 +556,57 @@ __MEM_SUBTRACT: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -615,47 +615,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -665,12 +665,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 72 "realloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -689,29 +689,29 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -720,111 +720,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -840,7 +840,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -848,44 +848,44 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 25 "str00.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/str01.asm b/tests/functional/str01.asm index 5a48022a4..dd12b25ab 100644 --- a/tests/functional/str01.asm +++ b/tests/functional/str01.asm @@ -37,19 +37,19 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "storestr2.asm" - + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication ; HL = address of string memory variable ; DE = address of 2n string. It just copies DE into (HL) ; freeing (HL) previously. - + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -57,25 +57,25 @@ __CALL_BACK__: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -84,41 +84,41 @@ __CALL_BACK__: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -126,25 +126,25 @@ __CALL_BACK__: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -153,39 +153,39 @@ __CALL_BACK__: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -193,56 +193,56 @@ __CALL_BACK__: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -251,57 +251,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -310,47 +310,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -360,55 +360,55 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 9 "storestr2.asm" - + __PISTORE_STR2: ; Indirect store temporary string at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR2: ld c, (hl) ; Dereferences HL inc hl ld h, (hl) ld l, c ; HL = *HL (real string variable address) - + __STORE_STR2: push hl ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = *HL (real string address) - + push de call __MEM_FREE pop de - + pop hl ld (hl), e inc hl ld (hl), d dec hl ; HL points to mem address variable. This might be useful in the future. - + ret - + #line 25 "str01.bas" #line 1 "str.asm" - + ; The STR$( ) BASIC function implementation - + ; Given a FP number in C ED LH ; Returns a pointer (in HL) to the memory heap ; containing the FP number string representation - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -416,25 +416,25 @@ __STORE_STR2: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -443,51 +443,51 @@ __STORE_STR2: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -495,12 +495,12 @@ __STORE_STR2: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -508,16 +508,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -529,27 +529,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -561,7 +561,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -569,15 +569,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -602,14 +602,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -617,53 +617,53 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 8 "str.asm" #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -680,9 +680,9 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK jp __FPSTACK_PUSH #line 9 "str.asm" #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -690,111 +690,111 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 10 "str.asm" - + __STR: - + __STR_FAST: - + PROC LOCAL __STR_END LOCAL RECLAIM2 LOCAL STK_END - + ld hl, (STK_END) push hl; Stores STK_END ld hl, (ATTR_T) ; Saves ATTR_T since it's changed by STR$ due to a ROM BUG push hl - + call __FPSTACK_PUSH ; Push number into stack rst 28h ; # Rom Calculator defb 2Eh ; # STR$(x) defb 38h ; # END CALC call __FPSTACK_POP ; Recovers string parameters to A ED CB (Only ED LH are important) - + pop hl ld (ATTR_T), hl ; Restores ATTR_T pop hl ld (STK_END), hl ; Balance STK_END to avoid STR$ bug - + push bc push de - + inc bc inc bc call __MEM_ALLOC ; HL Points to new block - + pop de pop bc - + push hl ld a, h or l jr z, __STR_END ; Return if NO MEMORY (NULL) - + push bc push de - ld (hl), c + ld (hl), c inc hl ld (hl), b inc hl ; Copies length - + ex de, hl ; HL = start of original string ldir ; Copies string content - + pop de ; Original (ROM-CALC) string pop bc ; Original Length - + __STR_END: ex de, hl inc bc - + call RECLAIM2 ; Frees TMP Memory pop hl ; String result - + ret - + RECLAIM2 EQU 19E8h STK_END EQU 5C65h - + ENDP - + #line 26 "str01.bas" #line 1 "u32tofreg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "u32tofreg.asm" __I8TOFREG: ld l, a @@ -803,35 +803,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -839,20 +839,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -860,32 +860,32 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 27 "str01.bas" - + ZXBASIC_USER_DATA: _b: DEFB 00 diff --git a/tests/functional/str02.asm b/tests/functional/str02.asm index 668462c49..3ab759a1c 100644 --- a/tests/functional/str02.asm +++ b/tests/functional/str02.asm @@ -52,10 +52,10 @@ __LABEL0: DEFB 6Fh DEFB 20h #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -63,25 +63,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -90,51 +90,51 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -142,12 +142,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -155,7 +155,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -163,10 +163,10 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -174,25 +174,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -201,39 +201,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -241,57 +241,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -303,27 +303,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -335,7 +335,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -343,15 +343,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -376,14 +376,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -391,34 +391,34 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 40 "str02.bas" #line 1 "storestr2.asm" - + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication ; HL = address of string memory variable ; DE = address of 2n string. It just copies DE into (HL) ; freeing (HL) previously. - + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -426,25 +426,25 @@ __MEM_SUBTRACT: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -453,38 +453,38 @@ __MEM_SUBTRACT: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -493,57 +493,57 @@ __MEM_SUBTRACT: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -552,47 +552,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -602,84 +602,84 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 9 "storestr2.asm" - + __PISTORE_STR2: ; Indirect store temporary string at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR2: ld c, (hl) ; Dereferences HL inc hl ld h, (hl) ld l, c ; HL = *HL (real string variable address) - + __STORE_STR2: push hl ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = *HL (real string address) - + push de call __MEM_FREE pop de - + pop hl ld (hl), e inc hl ld (hl), d dec hl ; HL points to mem address variable. This might be useful in the future. - + ret - + #line 41 "str02.bas" #line 1 "str.asm" - + ; The STR$( ) BASIC function implementation - + ; Given a FP number in C ED LH ; Returns a pointer (in HL) to the memory heap ; containing the FP number string representation - - + + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -696,9 +696,9 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK jp __FPSTACK_PUSH #line 9 "str.asm" #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -706,174 +706,174 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 10 "str.asm" - + __STR: - + __STR_FAST: - + PROC LOCAL __STR_END LOCAL RECLAIM2 LOCAL STK_END - + ld hl, (STK_END) push hl; Stores STK_END ld hl, (ATTR_T) ; Saves ATTR_T since it's changed by STR$ due to a ROM BUG push hl - + call __FPSTACK_PUSH ; Push number into stack rst 28h ; # Rom Calculator defb 2Eh ; # STR$(x) defb 38h ; # END CALC call __FPSTACK_POP ; Recovers string parameters to A ED CB (Only ED LH are important) - + pop hl ld (ATTR_T), hl ; Restores ATTR_T pop hl ld (STK_END), hl ; Balance STK_END to avoid STR$ bug - + push bc push de - + inc bc inc bc call __MEM_ALLOC ; HL Points to new block - + pop de pop bc - + push hl ld a, h or l jr z, __STR_END ; Return if NO MEMORY (NULL) - + push bc push de - ld (hl), c + ld (hl), c inc hl ld (hl), b inc hl ; Copies length - + ex de, hl ; HL = start of original string ldir ; Copies string content - + pop de ; Original (ROM-CALC) string pop bc ; Original Length - + __STR_END: ex de, hl inc bc - + call RECLAIM2 ; Frees TMP Memory pop hl ; String result - + ret - + RECLAIM2 EQU 19E8h STK_END EQU 5C65h - + ENDP - + #line 42 "str02.bas" #line 1 "strcat.asm" - - + + #line 1 "strlen.asm" - + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL - + __STRLEN: ; Direct FASTCALL entry ld a, h or l ret z - + ld a, (hl) inc hl ld h, (hl) ; LEN(str) in HL ld l, a ret - - + + #line 3 "strcat.asm" - + __ADDSTR: ; Implements c$ = a$ + b$ ; hl = &a$, de = &b$ (pointers) - - + + __STRCAT2: ; This routine creates a new string in dynamic space ; making room for it. Then copies a$ + b$ into it. ; HL = a$, DE = b$ - + PROC - + LOCAL __STR_CONT LOCAL __STRCATEND - + push hl call __STRLEN ld c, l ld b, h ; BC = LEN(a$) ex (sp), hl ; (SP) = LEN (a$), HL = a$ push hl ; Saves pointer to a$ - + inc bc inc bc ; +2 bytes to store length - + ex de, hl push hl call __STRLEN ; HL = len(b$) - + add hl, bc ; Total str length => 2 + len(a$) + len(b$) - + ld c, l ld b, h ; BC = Total str length + 2 - call __MEM_ALLOC - pop de ; HL = c$, DE = b$ - + call __MEM_ALLOC + pop de ; HL = c$, DE = b$ + ex de, hl ; HL = b$, DE = c$ - ex (sp), hl ; HL = a$, (SP) = b$ - + ex (sp), hl ; HL = a$, (SP) = b$ + exx - pop de ; D'E' = b$ + pop de ; D'E' = b$ exx - + pop bc ; LEN(a$) - + ld a, d or e ret z ; If no memory: RETURN - + __STR_CONT: push de ; Address of c$ - + ld a, h or l jr nz, __STR_CONT1 ; If len(a$) != 0 do copy - + ; a$ is NULL => uses HL = DE for transfer ld h, d ld l, e ld (hl), a ; This will copy 00 00 at (DE) location - inc de ; + inc de ; dec bc ; Ensure BC will be set to 1 in the next step - + __STR_CONT1: ; Copies a$ (HL) into c$ (DE) - inc bc + inc bc inc bc ; BC = BC + 2 ldir ; MEMCOPY: c$ = a$ pop hl ; HL = c$ - + exx push de ; Recovers b$; A ex hl,hl' would be very handy exx - - pop de ; DE = b$ - + + pop de ; DE = b$ + __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ; NOTE: Both DE, BC and AF are modified and lost ; Returns HL (pointer to a$) @@ -881,83 +881,83 @@ __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ld a, d or e ret z ; Returns if de is NULL (nothing to copy) - + push hl ; Saves HL to return it later - + ld c, (hl) inc hl ld b, (hl) inc hl add hl, bc ; HL = end of (a$) string ; bc = len(a$) push bc ; Saves LEN(a$) for later - + ex de, hl ; DE = end of string (Begin of copy addr) ld c, (hl) inc hl ld b, (hl) ; BC = len(b$) - + ld a, b or c jr z, __STRCATEND; Return if len(b$) == 0 - + push bc ; Save LEN(b$) inc hl ; Skip 2nd byte of len(b$) ldir ; Concatenate b$ - + pop bc ; Recovers length (b$) pop hl ; Recovers length (a$) add hl, bc ; HL = LEN(a$) + LEN(b$) = LEN(a$+b$) ex de, hl ; DE = LEN(a$+b$) pop hl - + ld (hl), e ; Updates new LEN and return inc hl ld (hl), d dec hl ret - + __STRCATEND: pop hl ; Removes Len(a$) pop hl ; Restores original HL, so HL = a$ ret - + ENDP - + #line 43 "str02.bas" #line 1 "u32tofreg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "u32tofreg.asm" __I8TOFREG: ld l, a @@ -966,35 +966,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -1002,20 +1002,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -1023,32 +1023,32 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 44 "str02.bas" - + ZXBASIC_USER_DATA: _b: DEFB 02h diff --git a/tests/functional/stradd.asm b/tests/functional/stradd.asm index efa6f801b..415cfa0b5 100644 --- a/tests/functional/stradd.asm +++ b/tests/functional/stradd.asm @@ -54,7 +54,7 @@ __LABEL1: DEFB 4Ch DEFB 44h #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -65,15 +65,15 @@ __LABEL1: ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -81,25 +81,25 @@ __LABEL1: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -108,52 +108,52 @@ __LABEL1: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -161,12 +161,12 @@ __LABEL1: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -174,7 +174,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -182,10 +182,10 @@ __STOP: ret #line 70 "realloc.asm" #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -193,25 +193,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -220,42 +220,42 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - + + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -263,25 +263,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -290,39 +290,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -330,57 +330,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -392,27 +392,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -424,7 +424,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -432,15 +432,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -465,14 +465,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -480,25 +480,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 71 "realloc.asm" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -506,25 +506,25 @@ __MEM_SUBTRACT: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -533,38 +533,38 @@ __MEM_SUBTRACT: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -573,57 +573,57 @@ __MEM_SUBTRACT: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -632,47 +632,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -682,12 +682,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 72 "realloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -706,29 +706,29 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -737,111 +737,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -857,7 +857,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -865,182 +865,182 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 42 "stradd.bas" #line 1 "storestr2.asm" - + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication ; HL = address of string memory variable ; DE = address of 2n string. It just copies DE into (HL) ; freeing (HL) previously. - - - + + + __PISTORE_STR2: ; Indirect store temporary string at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR2: ld c, (hl) ; Dereferences HL inc hl ld h, (hl) ld l, c ; HL = *HL (real string variable address) - + __STORE_STR2: push hl ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = *HL (real string address) - + push de call __MEM_FREE pop de - + pop hl ld (hl), e inc hl ld (hl), d dec hl ; HL points to mem address variable. This might be useful in the future. - + ret - + #line 43 "stradd.bas" #line 1 "strcat.asm" - - + + #line 1 "strlen.asm" - + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL - + __STRLEN: ; Direct FASTCALL entry ld a, h or l ret z - + ld a, (hl) inc hl ld h, (hl) ; LEN(str) in HL ld l, a ret - - + + #line 3 "strcat.asm" - + __ADDSTR: ; Implements c$ = a$ + b$ ; hl = &a$, de = &b$ (pointers) - - + + __STRCAT2: ; This routine creates a new string in dynamic space ; making room for it. Then copies a$ + b$ into it. ; HL = a$, DE = b$ - + PROC - + LOCAL __STR_CONT LOCAL __STRCATEND - + push hl call __STRLEN ld c, l ld b, h ; BC = LEN(a$) ex (sp), hl ; (SP) = LEN (a$), HL = a$ push hl ; Saves pointer to a$ - + inc bc inc bc ; +2 bytes to store length - + ex de, hl push hl call __STRLEN ; HL = len(b$) - + add hl, bc ; Total str length => 2 + len(a$) + len(b$) - + ld c, l ld b, h ; BC = Total str length + 2 - call __MEM_ALLOC - pop de ; HL = c$, DE = b$ - + call __MEM_ALLOC + pop de ; HL = c$, DE = b$ + ex de, hl ; HL = b$, DE = c$ - ex (sp), hl ; HL = a$, (SP) = b$ - + ex (sp), hl ; HL = a$, (SP) = b$ + exx - pop de ; D'E' = b$ + pop de ; D'E' = b$ exx - + pop bc ; LEN(a$) - + ld a, d or e ret z ; If no memory: RETURN - + __STR_CONT: push de ; Address of c$ - + ld a, h or l jr nz, __STR_CONT1 ; If len(a$) != 0 do copy - + ; a$ is NULL => uses HL = DE for transfer ld h, d ld l, e ld (hl), a ; This will copy 00 00 at (DE) location - inc de ; + inc de ; dec bc ; Ensure BC will be set to 1 in the next step - + __STR_CONT1: ; Copies a$ (HL) into c$ (DE) - inc bc + inc bc inc bc ; BC = BC + 2 ldir ; MEMCOPY: c$ = a$ pop hl ; HL = c$ - + exx push de ; Recovers b$; A ex hl,hl' would be very handy exx - - pop de ; DE = b$ - + + pop de ; DE = b$ + __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ; NOTE: Both DE, BC and AF are modified and lost ; Returns HL (pointer to a$) @@ -1048,50 +1048,50 @@ __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ld a, d or e ret z ; Returns if de is NULL (nothing to copy) - + push hl ; Saves HL to return it later - + ld c, (hl) inc hl ld b, (hl) inc hl add hl, bc ; HL = end of (a$) string ; bc = len(a$) push bc ; Saves LEN(a$) for later - + ex de, hl ; DE = end of string (Begin of copy addr) ld c, (hl) inc hl ld b, (hl) ; BC = len(b$) - + ld a, b or c jr z, __STRCATEND; Return if len(b$) == 0 - + push bc ; Save LEN(b$) inc hl ; Skip 2nd byte of len(b$) ldir ; Concatenate b$ - + pop bc ; Recovers length (b$) pop hl ; Recovers length (a$) add hl, bc ; HL = LEN(a$) + LEN(b$) = LEN(a$+b$) ex de, hl ; DE = LEN(a$+b$) pop hl - + ld (hl), e ; Updates new LEN and return inc hl ld (hl), d dec hl ret - + __STRCATEND: pop hl ; Removes Len(a$) pop hl ; Restores original HL, so HL = a$ ret - + ENDP - + #line 44 "stradd.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/strbase.asm b/tests/functional/strbase.asm index 4ba2a71d8..6c91ed27e 100644 --- a/tests/functional/strbase.asm +++ b/tests/functional/strbase.asm @@ -64,21 +64,21 @@ __LABEL1: DEFW 0001h DEFB 6Fh #line 1 "letsubstr.asm" - + ; Substring assigment eg. LET a$(p0 TO p1) = "xxxx" ; HL = Start of string ; TOP of the stack -> p1 (16 bit, unsigned) - ; TOP -1 of the stack -> p0 register + ; TOP -1 of the stack -> p0 register ; TOP -2 Flag (popped out in A register) ; A Register => 0 if HL is not freed from memory ; => Not 0 if HL must be freed from memory on exit ; TOP -3 B$ address - + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -86,25 +86,25 @@ __LABEL1: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -113,41 +113,41 @@ __LABEL1: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -155,25 +155,25 @@ __LABEL1: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -182,39 +182,39 @@ __LABEL1: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -222,56 +222,56 @@ __LABEL1: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -280,57 +280,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -339,47 +339,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -389,92 +389,92 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 11 "letsubstr.asm" - + __LETSUBSTR: PROC - + LOCAL __CONT0 LOCAL __CONT1 LOCAL __CONT2 LOCAL __FREE_STR LOCAL __FREE_STR0 - + exx pop hl ; Return address pop de ; p1 pop bc ; p0 exx - + pop af ; Flag ex af, af' ; Save it for later - + pop de ; B$ - + exx push hl ; push ret addr back exx - + ld a, h or l jp z, __FREE_STR0 ; Return if null - + ld c, (hl) inc hl ld b, (hl) ; BC = Str length inc hl ; HL = String start push bc - + exx ex de, hl or a sbc hl, bc ; HL = Length of string requester by user inc hl ; len (a$(p0 TO p1)) = p1 - p0 + 1 ex de, hl ; Saves it in DE - + pop hl ; HL = String length exx jp c, __FREE_STR0 ; Return if greather exx ; Return if p0 > p1 - + or a sbc hl, bc ; P0 >= String length? exx - + jp z, __FREE_STR0 ; Return if equal jp c, __FREE_STR0 ; Return if greather - + exx add hl, bc ; Add it back - + sbc hl, de ; Length of substring > string => Truncate it add hl, de ; add it back jr nc, __CONT0 ; Length of substring within a$ - + ld d, h ld e, l ; Truncate length of substring to fit within the strlen - + __CONT0: ; At this point DE = Length of subtring to copy ; BC = start of char to copy push de - + push bc exx pop bc - + add hl, bc ; Start address (within a$) so copy from b$ (in DE) - + push hl exx pop hl ; Start address (within a$) so copy from b$ (in DE) - + ld b, d ; Length of string ld c, e - - ld (hl), ' ' + + ld (hl), ' ' ld d, h ld e, l inc de @@ -482,33 +482,33 @@ __CONT0: ; At this point DE = Length of subtring to copy ld a, b or c jr z, __CONT2 - + ; At this point HL = DE = Start of Write zone in a$ ; BC = Number of chars to write - + ldir - + __CONT2: - + pop bc ; Recovers Length of string to copy exx ex de, hl ; HL = Source, DE = Target - + ld a, h or l jp z, __FREE_STR ; Return if B$ is NULL - + ld c, (hl) inc hl ld b, (hl) inc hl - + ld a, b or c jp z, __FREE_STR ; Return if len(b$) = 0 - + ; Now if len(b$) < len(char to copy), copy only len(b$) chars - + push de push hl push bc @@ -518,38 +518,38 @@ __CONT2: sbc hl, bc add hl, bc jr nc, __CONT1 - + ; If len(b$) < len(to copy) ld b, h ; BC = len(to copy) ld c, l - + __CONT1: - pop hl + pop hl pop de ldir ; Copy b$ into a$(x to y) - + exx ex de, hl - + __FREE_STR0: ex de, hl - + __FREE_STR: ex af, af' - or a ; If not 0, free + or a ; If not 0, free jp nz, __MEM_FREE ret - + ENDP - + #line 52 "strbase.bas" #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -557,25 +557,25 @@ __FREE_STR: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -584,51 +584,51 @@ __FREE_STR: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -636,12 +636,12 @@ __FREE_STR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -649,16 +649,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -670,27 +670,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -702,7 +702,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -710,15 +710,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -743,14 +743,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -758,25 +758,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -785,30 +785,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -816,7 +816,7 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 53 "strbase.bas" #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -827,15 +827,15 @@ __LOADSTR: ; __FASTCALL__ entry ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -843,25 +843,25 @@ __LOADSTR: ; __FASTCALL__ entry ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -870,42 +870,42 @@ __LOADSTR: ; __FASTCALL__ entry ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - - - - + + + + + + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -924,29 +924,29 @@ __LOADSTR: ; __FASTCALL__ entry ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -955,111 +955,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -1075,7 +1075,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -1083,144 +1083,144 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 54 "strbase.bas" #line 1 "storestr2.asm" - + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication ; HL = address of string memory variable ; DE = address of 2n string. It just copies DE into (HL) ; freeing (HL) previously. - - - + + + __PISTORE_STR2: ; Indirect store temporary string at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR2: ld c, (hl) ; Dereferences HL inc hl ld h, (hl) ld l, c ; HL = *HL (real string variable address) - + __STORE_STR2: push hl ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = *HL (real string address) - + push de call __MEM_FREE pop de - + pop hl ld (hl), e inc hl ld (hl), d dec hl ; HL points to mem address variable. This might be useful in the future. - + ret - + #line 55 "strbase.bas" #line 1 "strslice.asm" - + ; String slicing library ; HL = Str pointer ; DE = String start ; BC = String character end ; A register => 0 => the HL pointer wont' be freed from the HEAP ; e.g. a$(5 TO 10) => HL = a$; DE = 5; BC = 10 - - ; This implements a$(X to Y) being X and Y first and + + ; This implements a$(X to Y) being X and Y first and ; last characters respectively. If X > Y, NULL is returned - + ; Otherwise returns a pointer to a$ FROM X to Y (starting from 0) ; if Y > len(a$), then a$ will be padded with spaces (reallocating - ; it in dynamic memory if needed). Returns pointer (HL) to resulting + ; it in dynamic memory if needed). Returns pointer (HL) to resulting ; string. NULL (0) if no memory for padding. ; - + #line 1 "strlen.asm" - + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL - + __STRLEN: ; Direct FASTCALL entry ld a, h or l ret z - + ld a, (hl) inc hl ld h, (hl) ; LEN(str) in HL ld l, a ret - - + + #line 18 "strslice.asm" - - - + + + __STRSLICE: ; Callee entry pop hl ; Return ADDRESS pop bc ; Last char pos pop de ; 1st char pos ex (sp), hl ; CALLEE. -> String start - + __STRSLICE_FAST: ; __FASTCALL__ Entry PROC - + LOCAL __CONT LOCAL __EMPTY LOCAL __FREE_ON_EXIT - + push hl ; Stores original HL pointer to be recovered on exit ex af, af' ; Saves A register for later - + push hl call __STRLEN - inc bc ; Last character position + 1 (string starts from 0) + inc bc ; Last character position + 1 (string starts from 0) or a sbc hl, bc ; Compares length with last char position jr nc, __CONT ; If Carry => We must copy to end of string @@ -1228,19 +1228,19 @@ __STRSLICE_FAST: ; __FASTCALL__ Entry ld b, h ld c, l ; Copy to the end of str ccf ; Clears Carry flag for next subtraction - + __CONT: - ld h, b + ld h, b ld l, c ; HL = Last char position to copy (1 for char 0, 2 for char 1, etc) sbc hl, de ; HL = LEN(a$) - DE => Number of chars to copy jr z, __EMPTY ; 0 Chars to copy => Return HL = 0 (NULL STR) jr c, __EMPTY ; If Carry => Nothing to return (NULL STR) - + ld b, h ld c, l ; BC = Number of chars to copy inc bc inc bc ; +2 bytes for string length number - + push bc push de call __MEM_ALLOC @@ -1249,15 +1249,15 @@ __CONT: ld a, h or l jr z, __EMPTY ; Return if NULL (no memory) - + dec bc dec bc ; Number of chars to copy (Len of slice) - + ld (hl), c inc hl ld (hl), b inc hl ; Stores new string length - + ex (sp), hl ; Pointer to A$ now in HL; Pointer to new string chars in Stack inc hl inc hl ; Skip string length @@ -1270,26 +1270,26 @@ __CONT: dec de ; Points to String LEN start ex de, hl ; Returns it in HL jr __FREE_ON_EXIT - + __EMPTY: ; Return NULL (empty) string pop hl ld hl, 0 ; Return NULL - - + + __FREE_ON_EXIT: ex af, af' ; Recover original A register ex (sp), hl ; Original HL pointer - + or a call nz, __MEM_FREE - + pop hl ; Recover result - ret - - ENDP - + ret + + ENDP + #line 56 "strbase.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/strbase2.asm b/tests/functional/strbase2.asm index 294ce144c..41bc0d083 100644 --- a/tests/functional/strbase2.asm +++ b/tests/functional/strbase2.asm @@ -73,21 +73,21 @@ __LABEL1: DEFW 0001h DEFB 6Fh #line 1 "letsubstr.asm" - + ; Substring assigment eg. LET a$(p0 TO p1) = "xxxx" ; HL = Start of string ; TOP of the stack -> p1 (16 bit, unsigned) - ; TOP -1 of the stack -> p0 register + ; TOP -1 of the stack -> p0 register ; TOP -2 Flag (popped out in A register) ; A Register => 0 if HL is not freed from memory ; => Not 0 if HL must be freed from memory on exit ; TOP -3 B$ address - + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -95,25 +95,25 @@ __LABEL1: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -122,41 +122,41 @@ __LABEL1: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -164,25 +164,25 @@ __LABEL1: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -191,39 +191,39 @@ __LABEL1: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -231,56 +231,56 @@ __LABEL1: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -289,57 +289,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -348,47 +348,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -398,92 +398,92 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 11 "letsubstr.asm" - + __LETSUBSTR: PROC - + LOCAL __CONT0 LOCAL __CONT1 LOCAL __CONT2 LOCAL __FREE_STR LOCAL __FREE_STR0 - + exx pop hl ; Return address pop de ; p1 pop bc ; p0 exx - + pop af ; Flag ex af, af' ; Save it for later - + pop de ; B$ - + exx push hl ; push ret addr back exx - + ld a, h or l jp z, __FREE_STR0 ; Return if null - + ld c, (hl) inc hl ld b, (hl) ; BC = Str length inc hl ; HL = String start push bc - + exx ex de, hl or a sbc hl, bc ; HL = Length of string requester by user inc hl ; len (a$(p0 TO p1)) = p1 - p0 + 1 ex de, hl ; Saves it in DE - + pop hl ; HL = String length exx jp c, __FREE_STR0 ; Return if greather exx ; Return if p0 > p1 - + or a sbc hl, bc ; P0 >= String length? exx - + jp z, __FREE_STR0 ; Return if equal jp c, __FREE_STR0 ; Return if greather - + exx add hl, bc ; Add it back - + sbc hl, de ; Length of substring > string => Truncate it add hl, de ; add it back jr nc, __CONT0 ; Length of substring within a$ - + ld d, h ld e, l ; Truncate length of substring to fit within the strlen - + __CONT0: ; At this point DE = Length of subtring to copy ; BC = start of char to copy push de - + push bc exx pop bc - + add hl, bc ; Start address (within a$) so copy from b$ (in DE) - + push hl exx pop hl ; Start address (within a$) so copy from b$ (in DE) - + ld b, d ; Length of string ld c, e - - ld (hl), ' ' + + ld (hl), ' ' ld d, h ld e, l inc de @@ -491,33 +491,33 @@ __CONT0: ; At this point DE = Length of subtring to copy ld a, b or c jr z, __CONT2 - + ; At this point HL = DE = Start of Write zone in a$ ; BC = Number of chars to write - + ldir - + __CONT2: - + pop bc ; Recovers Length of string to copy exx ex de, hl ; HL = Source, DE = Target - + ld a, h or l jp z, __FREE_STR ; Return if B$ is NULL - + ld c, (hl) inc hl ld b, (hl) inc hl - + ld a, b or c jp z, __FREE_STR ; Return if len(b$) = 0 - + ; Now if len(b$) < len(char to copy), copy only len(b$) chars - + push de push hl push bc @@ -527,38 +527,38 @@ __CONT2: sbc hl, bc add hl, bc jr nc, __CONT1 - + ; If len(b$) < len(to copy) ld b, h ; BC = len(to copy) ld c, l - + __CONT1: - pop hl + pop hl pop de ldir ; Copy b$ into a$(x to y) - + exx ex de, hl - + __FREE_STR0: ex de, hl - + __FREE_STR: ex af, af' - or a ; If not 0, free + or a ; If not 0, free jp nz, __MEM_FREE ret - + ENDP - + #line 60 "strbase2.bas" #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -566,25 +566,25 @@ __FREE_STR: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -593,51 +593,51 @@ __FREE_STR: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -645,12 +645,12 @@ __FREE_STR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -658,16 +658,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -679,27 +679,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -711,7 +711,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -719,15 +719,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -752,14 +752,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -767,25 +767,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -794,30 +794,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -825,22 +825,22 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 61 "strbase2.bas" #line 1 "print_eol_attr.asm" - + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes - + #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -848,46 +848,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -900,67 +900,67 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - - - + + + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -969,17 +969,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -987,26 +987,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -1020,45 +1020,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -1069,28 +1069,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -1098,28 +1098,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -1128,83 +1128,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -1213,32 +1213,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -1248,7 +1248,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -1256,20 +1256,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -1279,7 +1279,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -1290,19 +1290,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -1312,7 +1312,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -1323,19 +1323,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -1345,7 +1345,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -1358,22 +1358,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -1382,79 +1382,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -1463,75 +1463,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -1541,7 +1541,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -1553,16 +1553,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1576,49 +1576,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1629,17 +1629,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1652,27 +1652,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1680,10 +1680,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1700,80 +1700,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1790,8 +1790,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1815,17 +1815,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1836,7 +1836,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1846,21 +1846,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1879,9 +1879,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1906,64 +1906,64 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 5 "print_eol_attr.asm" - - + + PRINT_EOL_ATTR: call PRINT_EOL jp COPY_ATTR #line 62 "strbase2.bas" #line 1 "printstr.asm" - - - - - - + + + + + + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1972,12 +1972,12 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 63 "strbase2.bas" #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -1988,15 +1988,15 @@ __PRINT_STR: ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -2004,25 +2004,25 @@ __PRINT_STR: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -2031,42 +2031,42 @@ __PRINT_STR: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - - - - + + + + + + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -2085,29 +2085,29 @@ __PRINT_STR: ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -2116,111 +2116,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -2236,7 +2236,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -2244,144 +2244,144 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 64 "strbase2.bas" #line 1 "storestr2.asm" - + ; Similar to __STORE_STR, but this one is called when ; the value of B$ if already duplicated onto the stack. ; So we needn't call STRASSING to create a duplication ; HL = address of string memory variable ; DE = address of 2n string. It just copies DE into (HL) ; freeing (HL) previously. - - - + + + __PISTORE_STR2: ; Indirect store temporary string at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR2: ld c, (hl) ; Dereferences HL inc hl ld h, (hl) ld l, c ; HL = *HL (real string variable address) - + __STORE_STR2: push hl ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = *HL (real string address) - + push de call __MEM_FREE pop de - + pop hl ld (hl), e inc hl ld (hl), d dec hl ; HL points to mem address variable. This might be useful in the future. - + ret - + #line 65 "strbase2.bas" #line 1 "strslice.asm" - + ; String slicing library ; HL = Str pointer ; DE = String start ; BC = String character end ; A register => 0 => the HL pointer wont' be freed from the HEAP ; e.g. a$(5 TO 10) => HL = a$; DE = 5; BC = 10 - - ; This implements a$(X to Y) being X and Y first and + + ; This implements a$(X to Y) being X and Y first and ; last characters respectively. If X > Y, NULL is returned - + ; Otherwise returns a pointer to a$ FROM X to Y (starting from 0) ; if Y > len(a$), then a$ will be padded with spaces (reallocating - ; it in dynamic memory if needed). Returns pointer (HL) to resulting + ; it in dynamic memory if needed). Returns pointer (HL) to resulting ; string. NULL (0) if no memory for padding. ; - + #line 1 "strlen.asm" - + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL - + __STRLEN: ; Direct FASTCALL entry ld a, h or l ret z - + ld a, (hl) inc hl ld h, (hl) ; LEN(str) in HL ld l, a ret - - + + #line 18 "strslice.asm" - - - + + + __STRSLICE: ; Callee entry pop hl ; Return ADDRESS pop bc ; Last char pos pop de ; 1st char pos ex (sp), hl ; CALLEE. -> String start - + __STRSLICE_FAST: ; __FASTCALL__ Entry PROC - + LOCAL __CONT LOCAL __EMPTY LOCAL __FREE_ON_EXIT - + push hl ; Stores original HL pointer to be recovered on exit ex af, af' ; Saves A register for later - + push hl call __STRLEN - inc bc ; Last character position + 1 (string starts from 0) + inc bc ; Last character position + 1 (string starts from 0) or a sbc hl, bc ; Compares length with last char position jr nc, __CONT ; If Carry => We must copy to end of string @@ -2389,19 +2389,19 @@ __STRSLICE_FAST: ; __FASTCALL__ Entry ld b, h ld c, l ; Copy to the end of str ccf ; Clears Carry flag for next subtraction - + __CONT: - ld h, b + ld h, b ld l, c ; HL = Last char position to copy (1 for char 0, 2 for char 1, etc) sbc hl, de ; HL = LEN(a$) - DE => Number of chars to copy jr z, __EMPTY ; 0 Chars to copy => Return HL = 0 (NULL STR) jr c, __EMPTY ; If Carry => Nothing to return (NULL STR) - + ld b, h ld c, l ; BC = Number of chars to copy inc bc inc bc ; +2 bytes for string length number - + push bc push de call __MEM_ALLOC @@ -2410,15 +2410,15 @@ __CONT: ld a, h or l jr z, __EMPTY ; Return if NULL (no memory) - + dec bc dec bc ; Number of chars to copy (Len of slice) - + ld (hl), c inc hl ld (hl), b inc hl ; Stores new string length - + ex (sp), hl ; Pointer to A$ now in HL; Pointer to new string chars in Stack inc hl inc hl ; Skip string length @@ -2431,26 +2431,26 @@ __CONT: dec de ; Points to String LEN start ex de, hl ; Returns it in HL jr __FREE_ON_EXIT - + __EMPTY: ; Return NULL (empty) string pop hl ld hl, 0 ; Return NULL - - + + __FREE_ON_EXIT: ex af, af' ; Recover original A register ex (sp), hl ; Original HL pointer - + or a call nz, __MEM_FREE - + pop hl ; Recover result - ret - - ENDP - + ret + + ENDP + #line 66 "strbase2.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/strict2.asm b/tests/functional/strict2.asm index d562c4692..9ea78030e 100644 --- a/tests/functional/strict2.asm +++ b/tests/functional/strict2.asm @@ -34,7 +34,7 @@ _anysub__leave: ld sp, ix pop ix ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/stringfunc.asm b/tests/functional/stringfunc.asm index 924ec9052..c1ebb02cb 100644 --- a/tests/functional/stringfunc.asm +++ b/tests/functional/stringfunc.asm @@ -50,10 +50,10 @@ __LABEL0: DEFB 6Ch DEFB 6Fh #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -61,25 +61,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -88,41 +88,41 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -130,25 +130,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -157,39 +157,39 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -197,56 +197,56 @@ __LABEL0: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -255,57 +255,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -314,47 +314,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -364,17 +364,17 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 38 "stringfunc.bas" #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -382,25 +382,25 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -409,51 +409,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -461,12 +461,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -474,16 +474,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -495,27 +495,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -527,7 +527,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -535,15 +535,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -568,14 +568,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -583,25 +583,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -610,37 +610,37 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) pop hl ; Recovers destiny in hl as result ret #line 39 "stringfunc.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/stringparam.asm b/tests/functional/stringparam.asm index 7d0dcf9df..46adf3f69 100644 --- a/tests/functional/stringparam.asm +++ b/tests/functional/stringparam.asm @@ -66,10 +66,10 @@ __LABEL0: DEFB 6Ch DEFB 6Fh #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -77,25 +77,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -104,41 +104,41 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -146,25 +146,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -173,39 +173,39 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -213,56 +213,56 @@ __LABEL0: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -271,57 +271,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -330,47 +330,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -380,17 +380,17 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 53 "stringparam.bas" #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -398,25 +398,25 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -425,51 +425,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -477,12 +477,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -490,16 +490,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -511,27 +511,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -543,7 +543,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -551,15 +551,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -584,14 +584,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -599,25 +599,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -626,30 +626,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -657,22 +657,22 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 54 "stringparam.bas" #line 1 "print_eol_attr.asm" - + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes - + #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -680,46 +680,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -732,67 +732,67 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - - - + + + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -801,17 +801,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -819,26 +819,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -852,45 +852,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -901,28 +901,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -930,28 +930,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -960,83 +960,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -1045,32 +1045,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -1080,7 +1080,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -1088,20 +1088,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -1111,7 +1111,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -1122,19 +1122,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -1144,7 +1144,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -1155,19 +1155,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -1177,7 +1177,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -1190,22 +1190,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -1214,79 +1214,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -1295,75 +1295,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -1373,7 +1373,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -1385,16 +1385,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1408,49 +1408,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1461,17 +1461,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1484,27 +1484,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1512,10 +1512,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1532,80 +1532,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1622,8 +1622,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1647,17 +1647,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1668,7 +1668,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1678,21 +1678,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1711,9 +1711,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1738,64 +1738,64 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 5 "print_eol_attr.asm" - - + + PRINT_EOL_ATTR: call PRINT_EOL jp COPY_ATTR #line 55 "stringparam.bas" #line 1 "printstr.asm" - - - - - - + + + + + + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1804,11 +1804,11 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 56 "stringparam.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/strlocal0.asm b/tests/functional/strlocal0.asm index ac50795cc..5b3eb9be3 100644 --- a/tests/functional/strlocal0.asm +++ b/tests/functional/strlocal0.asm @@ -70,10 +70,10 @@ __LABEL0: DEFB 6Ch DEFB 64h #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -81,25 +81,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -108,41 +108,41 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -150,25 +150,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -177,39 +177,39 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -217,56 +217,56 @@ __LABEL0: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -275,57 +275,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -334,47 +334,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -384,27 +384,27 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 57 "strlocal0.bas" #line 1 "print_eol_attr.asm" - + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes - + #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -412,46 +412,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -464,43 +464,43 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -508,12 +508,12 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -521,51 +521,51 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "in_screen.asm" - + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -574,17 +574,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -592,26 +592,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -625,45 +625,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -674,28 +674,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -703,28 +703,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -733,83 +733,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -818,32 +818,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -853,7 +853,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -861,20 +861,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -884,7 +884,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -895,19 +895,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -917,7 +917,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -928,19 +928,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -950,7 +950,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -963,22 +963,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -987,79 +987,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -1068,75 +1068,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -1146,7 +1146,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -1158,16 +1158,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1181,49 +1181,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1234,17 +1234,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1257,27 +1257,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1285,10 +1285,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1305,80 +1305,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1395,8 +1395,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1420,17 +1420,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1441,7 +1441,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1451,21 +1451,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1484,9 +1484,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1511,64 +1511,64 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 5 "print_eol_attr.asm" - - + + PRINT_EOL_ATTR: call PRINT_EOL jp COPY_ATTR #line 58 "strlocal0.bas" #line 1 "printstr.asm" - - - - - - + + + + + + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1577,20 +1577,20 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 59 "strlocal0.bas" #line 1 "pstorestr.asm" - + ; vim:ts=4:et:sw=4 - ; + ; ; Stores an string (pointer to the HEAP by DE) into the address pointed ; by (IX + BC). A new copy of the string is created into the HEAP ; - + #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -1601,15 +1601,15 @@ __PRINT_STR: ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1617,25 +1617,25 @@ __PRINT_STR: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1644,43 +1644,43 @@ __PRINT_STR: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1688,25 +1688,25 @@ __PRINT_STR: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1715,40 +1715,40 @@ __PRINT_STR: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - - + + + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -1760,27 +1760,27 @@ __PRINT_STR: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -1792,7 +1792,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -1800,15 +1800,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -1833,14 +1833,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -1848,23 +1848,23 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 71 "realloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -1883,29 +1883,29 @@ __MEM_SUBTRACT: ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -1914,111 +1914,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -2034,7 +2034,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -2042,52 +2042,52 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 8 "pstorestr.asm" - + __PSTORE_STR: push ix pop hl add hl, bc jp __STORE_STR - + #line 60 "strlocal0.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/strparam0.asm b/tests/functional/strparam0.asm index 0cd578fb8..da8a5a727 100644 --- a/tests/functional/strparam0.asm +++ b/tests/functional/strparam0.asm @@ -96,10 +96,10 @@ __LABEL0: DEFB 6Ch DEFB 64h #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -107,25 +107,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -134,41 +134,41 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -176,25 +176,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -203,39 +203,39 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -243,56 +243,56 @@ __LABEL0: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -301,57 +301,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -360,47 +360,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -410,17 +410,17 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 83 "strparam0.bas" #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -428,25 +428,25 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -455,51 +455,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -507,12 +507,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -520,16 +520,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -541,27 +541,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -573,7 +573,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -581,15 +581,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -614,14 +614,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -629,25 +629,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -656,30 +656,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -687,22 +687,22 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 84 "strparam0.bas" #line 1 "print_eol_attr.asm" - + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes - + #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -710,46 +710,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -762,67 +762,67 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - - - + + + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -831,17 +831,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -849,26 +849,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -882,45 +882,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -931,28 +931,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -960,28 +960,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -990,83 +990,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -1075,32 +1075,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -1110,7 +1110,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -1118,20 +1118,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -1141,7 +1141,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -1152,19 +1152,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -1174,7 +1174,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -1185,19 +1185,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -1207,7 +1207,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -1220,22 +1220,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -1244,79 +1244,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -1325,75 +1325,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -1403,7 +1403,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -1415,16 +1415,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1438,49 +1438,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1491,17 +1491,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1514,27 +1514,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1542,10 +1542,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1562,80 +1562,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1652,8 +1652,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1677,17 +1677,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1698,7 +1698,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1708,21 +1708,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1741,9 +1741,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1768,64 +1768,64 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 5 "print_eol_attr.asm" - - + + PRINT_EOL_ATTR: call PRINT_EOL jp COPY_ATTR #line 85 "strparam0.bas" #line 1 "printstr.asm" - - - - - - + + + + + + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1834,11 +1834,11 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 86 "strparam0.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/strparam1.asm b/tests/functional/strparam1.asm index e8fc1654d..a2814b633 100644 --- a/tests/functional/strparam1.asm +++ b/tests/functional/strparam1.asm @@ -80,10 +80,10 @@ __LABEL0: DEFB 6Fh DEFB 20h #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -91,25 +91,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -118,51 +118,51 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -170,12 +170,12 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -183,7 +183,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -191,10 +191,10 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -202,25 +202,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -229,39 +229,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -269,57 +269,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -331,27 +331,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -363,7 +363,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -371,15 +371,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -404,14 +404,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -419,25 +419,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 68 "strparam1.bas" #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -445,25 +445,25 @@ __MEM_SUBTRACT: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -472,38 +472,38 @@ __MEM_SUBTRACT: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -512,57 +512,57 @@ __MEM_SUBTRACT: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -571,47 +571,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -621,20 +621,20 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 69 "strparam1.bas" #line 1 "pstorestr.asm" - + ; vim:ts=4:et:sw=4 - ; + ; ; Stores an string (pointer to the HEAP by DE) into the address pointed ; by (IX + BC). A new copy of the string is created into the HEAP ; - + #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -645,15 +645,15 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -661,25 +661,25 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -688,42 +688,42 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - - - - + + + + + + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -742,29 +742,29 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -773,111 +773,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -893,7 +893,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -901,93 +901,93 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 8 "pstorestr.asm" - + __PSTORE_STR: push ix pop hl add hl, bc jp __STORE_STR - + #line 70 "strparam1.bas" #line 1 "str.asm" - + ; The STR$( ) BASIC function implementation - + ; Given a FP number in C ED LH ; Returns a pointer (in HL) to the memory heap ; containing the FP number string representation - - + + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -1004,9 +1004,9 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK jp __FPSTACK_PUSH #line 9 "str.asm" #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -1014,174 +1014,174 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 10 "str.asm" - + __STR: - + __STR_FAST: - + PROC LOCAL __STR_END LOCAL RECLAIM2 LOCAL STK_END - + ld hl, (STK_END) push hl; Stores STK_END ld hl, (ATTR_T) ; Saves ATTR_T since it's changed by STR$ due to a ROM BUG push hl - + call __FPSTACK_PUSH ; Push number into stack rst 28h ; # Rom Calculator defb 2Eh ; # STR$(x) defb 38h ; # END CALC call __FPSTACK_POP ; Recovers string parameters to A ED CB (Only ED LH are important) - + pop hl ld (ATTR_T), hl ; Restores ATTR_T pop hl ld (STK_END), hl ; Balance STK_END to avoid STR$ bug - + push bc push de - + inc bc inc bc call __MEM_ALLOC ; HL Points to new block - + pop de pop bc - + push hl ld a, h or l jr z, __STR_END ; Return if NO MEMORY (NULL) - + push bc push de - ld (hl), c + ld (hl), c inc hl ld (hl), b inc hl ; Copies length - + ex de, hl ; HL = start of original string ldir ; Copies string content - + pop de ; Original (ROM-CALC) string pop bc ; Original Length - + __STR_END: ex de, hl inc bc - + call RECLAIM2 ; Frees TMP Memory pop hl ; String result - + ret - + RECLAIM2 EQU 19E8h STK_END EQU 5C65h - + ENDP - + #line 71 "strparam1.bas" #line 1 "strcat.asm" - - + + #line 1 "strlen.asm" - + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL - + __STRLEN: ; Direct FASTCALL entry ld a, h or l ret z - + ld a, (hl) inc hl ld h, (hl) ; LEN(str) in HL ld l, a ret - - + + #line 3 "strcat.asm" - + __ADDSTR: ; Implements c$ = a$ + b$ ; hl = &a$, de = &b$ (pointers) - - + + __STRCAT2: ; This routine creates a new string in dynamic space ; making room for it. Then copies a$ + b$ into it. ; HL = a$, DE = b$ - + PROC - + LOCAL __STR_CONT LOCAL __STRCATEND - + push hl call __STRLEN ld c, l ld b, h ; BC = LEN(a$) ex (sp), hl ; (SP) = LEN (a$), HL = a$ push hl ; Saves pointer to a$ - + inc bc inc bc ; +2 bytes to store length - + ex de, hl push hl call __STRLEN ; HL = len(b$) - + add hl, bc ; Total str length => 2 + len(a$) + len(b$) - + ld c, l ld b, h ; BC = Total str length + 2 - call __MEM_ALLOC - pop de ; HL = c$, DE = b$ - + call __MEM_ALLOC + pop de ; HL = c$, DE = b$ + ex de, hl ; HL = b$, DE = c$ - ex (sp), hl ; HL = a$, (SP) = b$ - + ex (sp), hl ; HL = a$, (SP) = b$ + exx - pop de ; D'E' = b$ + pop de ; D'E' = b$ exx - + pop bc ; LEN(a$) - + ld a, d or e ret z ; If no memory: RETURN - + __STR_CONT: push de ; Address of c$ - + ld a, h or l jr nz, __STR_CONT1 ; If len(a$) != 0 do copy - + ; a$ is NULL => uses HL = DE for transfer ld h, d ld l, e ld (hl), a ; This will copy 00 00 at (DE) location - inc de ; + inc de ; dec bc ; Ensure BC will be set to 1 in the next step - + __STR_CONT1: ; Copies a$ (HL) into c$ (DE) - inc bc + inc bc inc bc ; BC = BC + 2 ldir ; MEMCOPY: c$ = a$ pop hl ; HL = c$ - + exx push de ; Recovers b$; A ex hl,hl' would be very handy exx - - pop de ; DE = b$ - + + pop de ; DE = b$ + __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ; NOTE: Both DE, BC and AF are modified and lost ; Returns HL (pointer to a$) @@ -1189,83 +1189,83 @@ __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ld a, d or e ret z ; Returns if de is NULL (nothing to copy) - + push hl ; Saves HL to return it later - + ld c, (hl) inc hl ld b, (hl) inc hl add hl, bc ; HL = end of (a$) string ; bc = len(a$) push bc ; Saves LEN(a$) for later - + ex de, hl ; DE = end of string (Begin of copy addr) ld c, (hl) inc hl ld b, (hl) ; BC = len(b$) - + ld a, b or c jr z, __STRCATEND; Return if len(b$) == 0 - + push bc ; Save LEN(b$) inc hl ; Skip 2nd byte of len(b$) ldir ; Concatenate b$ - + pop bc ; Recovers length (b$) pop hl ; Recovers length (a$) add hl, bc ; HL = LEN(a$) + LEN(b$) = LEN(a$+b$) ex de, hl ; DE = LEN(a$+b$) pop hl - + ld (hl), e ; Updates new LEN and return inc hl ld (hl), d dec hl ret - + __STRCATEND: pop hl ; Removes Len(a$) pop hl ; Restores original HL, so HL = a$ ret - + ENDP - + #line 72 "strparam1.bas" #line 1 "u32tofreg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "u32tofreg.asm" __I8TOFREG: ld l, a @@ -1274,35 +1274,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -1310,20 +1310,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -1331,32 +1331,32 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 73 "strparam1.bas" - + ZXBASIC_USER_DATA: _b: DEFB 02h diff --git a/tests/functional/strparam2.asm b/tests/functional/strparam2.asm index 8ce2974a9..931fb804d 100644 --- a/tests/functional/strparam2.asm +++ b/tests/functional/strparam2.asm @@ -83,22 +83,22 @@ __LABEL0: DEFB 49h DEFB 43h #line 1 "print_eol_attr.asm" - + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes - + #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -106,46 +106,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -158,43 +158,43 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -202,12 +202,12 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -215,51 +215,51 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "in_screen.asm" - + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -268,17 +268,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -286,26 +286,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -319,45 +319,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -368,28 +368,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -397,28 +397,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -427,83 +427,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -512,32 +512,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -547,7 +547,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -555,20 +555,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -578,7 +578,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -589,19 +589,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -611,7 +611,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -622,19 +622,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -644,7 +644,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -657,22 +657,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -681,79 +681,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -762,75 +762,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -840,7 +840,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -852,16 +852,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -875,49 +875,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -928,17 +928,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -951,27 +951,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -979,10 +979,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -999,80 +999,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1089,8 +1089,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1114,17 +1114,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1135,7 +1135,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1145,21 +1145,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1178,9 +1178,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1205,27 +1205,27 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 5 "print_eol_attr.asm" - - + + PRINT_EOL_ATTR: call PRINT_EOL jp COPY_ATTR #line 70 "strparam2.bas" #line 1 "printstr.asm" - - - - + + + + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1233,25 +1233,25 @@ PRINT_EOL_ATTR: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1260,41 +1260,41 @@ PRINT_EOL_ATTR: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1302,25 +1302,25 @@ PRINT_EOL_ATTR: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1329,39 +1329,39 @@ PRINT_EOL_ATTR: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -1369,56 +1369,56 @@ PRINT_EOL_ATTR: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -1427,57 +1427,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -1486,47 +1486,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -1536,51 +1536,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 5 "printstr.asm" - + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1589,12 +1589,12 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 71 "strparam2.bas" #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -1605,15 +1605,15 @@ __PRINT_STR: ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1621,25 +1621,25 @@ __PRINT_STR: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1648,43 +1648,43 @@ __PRINT_STR: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1692,25 +1692,25 @@ __PRINT_STR: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1719,40 +1719,40 @@ __PRINT_STR: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - - + + + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -1764,27 +1764,27 @@ __PRINT_STR: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -1796,7 +1796,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -1804,15 +1804,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -1837,14 +1837,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -1852,23 +1852,23 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 71 "realloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -1887,29 +1887,29 @@ __MEM_SUBTRACT: ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -1918,111 +1918,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -2038,7 +2038,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -2046,44 +2046,44 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 72 "strparam2.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/strparam3.asm b/tests/functional/strparam3.asm index 3129bd5ea..30f547df0 100644 --- a/tests/functional/strparam3.asm +++ b/tests/functional/strparam3.asm @@ -90,10 +90,10 @@ __LABEL0: DEFB 49h DEFB 43h #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -101,25 +101,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -128,41 +128,41 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -170,25 +170,25 @@ __LABEL0: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -197,39 +197,39 @@ __LABEL0: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -237,56 +237,56 @@ __LABEL0: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -295,57 +295,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -354,47 +354,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -404,17 +404,17 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 77 "strparam3.bas" #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -422,25 +422,25 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -449,51 +449,51 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -501,12 +501,12 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -514,16 +514,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -535,27 +535,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -567,7 +567,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -575,15 +575,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -608,14 +608,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -623,25 +623,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -650,30 +650,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -681,22 +681,22 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 78 "strparam3.bas" #line 1 "print_eol_attr.asm" - + ; Calls PRINT_EOL and then COPY_ATTR, so saves ; 3 bytes - + #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -704,46 +704,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -756,67 +756,67 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - - - + + + + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -825,17 +825,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -843,26 +843,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -876,45 +876,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -925,28 +925,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -954,28 +954,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -984,83 +984,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -1069,32 +1069,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -1104,7 +1104,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -1112,20 +1112,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -1135,7 +1135,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -1146,19 +1146,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -1168,7 +1168,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -1179,19 +1179,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -1201,7 +1201,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -1214,22 +1214,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -1238,79 +1238,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -1319,75 +1319,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -1397,7 +1397,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -1409,16 +1409,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -1432,49 +1432,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -1485,17 +1485,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -1508,27 +1508,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -1536,10 +1536,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -1556,80 +1556,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1646,8 +1646,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1671,17 +1671,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1692,7 +1692,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1702,21 +1702,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1735,9 +1735,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1762,64 +1762,64 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 5 "print_eol_attr.asm" - - + + PRINT_EOL_ATTR: call PRINT_EOL jp COPY_ATTR #line 79 "strparam3.bas" #line 1 "printstr.asm" - - - - - - + + + + + + ; PRINT command routine ; Prints string pointed by HL - + PRINT_STR: __PRINTSTR: ; __FASTCALL__ Entry to print_string PROC LOCAL __PRINT_STR_LOOP LOCAL __PRINT_STR_END - + ld d, a ; Saves A reg (Flag) for later - + ld a, h or l ret z ; Return if the pointer is NULL - + push hl - + ld c, (hl) inc hl ld b, (hl) inc hl ; BC = LEN(a$); HL = &a$ - + __PRINT_STR_LOOP: ld a, b or c jr z, __PRINT_STR_END ; END if BC (counter = 0) - + ld a, (hl) call __PRINTCHAR inc hl dec bc jp __PRINT_STR_LOOP - + __PRINT_STR_END: pop hl ld a, d ; Recovers A flag or a ; If not 0 this is a temporary string. Free it ret z jp __MEM_FREE ; Frees str from heap and return from there - + __PRINT_STR: ; Fastcall Entry ; It ONLY prints strings @@ -1828,11 +1828,11 @@ __PRINT_STR: push hl ; Push str address for later ld d, a ; Saves a FLAG jp __PRINT_STR_LOOP - + ENDP - + #line 80 "strparam3.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/strsigil.asm b/tests/functional/strsigil.asm index 12a87e851..60218c2d1 100644 --- a/tests/functional/strsigil.asm +++ b/tests/functional/strsigil.asm @@ -47,13 +47,13 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "asc.asm" - + ; Returns the ascii code for the given str #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -61,25 +61,25 @@ __CALL_BACK__: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -88,41 +88,41 @@ __CALL_BACK__: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -130,25 +130,25 @@ __CALL_BACK__: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -157,39 +157,39 @@ __CALL_BACK__: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -197,56 +197,56 @@ __CALL_BACK__: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -255,57 +255,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -314,47 +314,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -364,91 +364,91 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 3 "asc.asm" - + __ASC: PROC LOCAL __ASC_END - + ex af, af' ; Saves free_mem flag - + ld a, h or l ret z ; NULL? return - + ld c, (hl) inc hl ld b, (hl) - + ld a, b or c jr z, __ASC_END ; No length? return - + inc hl ld a, (hl) dec hl - + __ASC_END: dec hl ex af, af' or a call nz, __MEM_FREE ; Free memory if needed - + ex af, af' ; Recover result - + ret ENDP #line 35 "strsigil.bas" #line 1 "ftou32reg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "ftou32reg.asm" - + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) PROC - + LOCAL __IS_FLOAT - + or a - jr nz, __IS_FLOAT + jr nz, __IS_FLOAT ; Here if it is a ZX ROM Integer - + ld h, c ld l, d ld a, e ; Takes sign: FF = -, 0 = + @@ -456,105 +456,105 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS inc a jp z, __NEG32 ; Negates if negative ret - + __IS_FLOAT: ; Jumps here if it is a true floating point number - ld h, e + ld h, e push hl ; Stores it for later (Contains Sign in H) - + push de push bc - + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + ;ld a, c ; Get exponent sub 128 ; Exponent -= 128 jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 - + __FTOU32REG_LOOP: exx ; Shift C'B' E'D' << 1, output bit stays in Carry sla d rl e rl b rl c - + exx ; Shift DEHL << 1, inserting the carry on the right rl l rl h rl e rl d - + djnz __FTOU32REG_LOOP - + __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative jp m, __NEG32 ; Negates DEHL - + ret - + ENDP - - + + __FTOU8: ; Converts float in C ED LH to Unsigned byte in A call __FTOU32REG ld a, l ret - + #line 36 "strsigil.bas" #line 1 "strslice.asm" - + ; String slicing library ; HL = Str pointer ; DE = String start ; BC = String character end ; A register => 0 => the HL pointer wont' be freed from the HEAP ; e.g. a$(5 TO 10) => HL = a$; DE = 5; BC = 10 - - ; This implements a$(X to Y) being X and Y first and + + ; This implements a$(X to Y) being X and Y first and ; last characters respectively. If X > Y, NULL is returned - + ; Otherwise returns a pointer to a$ FROM X to Y (starting from 0) ; if Y > len(a$), then a$ will be padded with spaces (reallocating - ; it in dynamic memory if needed). Returns pointer (HL) to resulting + ; it in dynamic memory if needed). Returns pointer (HL) to resulting ; string. NULL (0) if no memory for padding. ; - + #line 1 "strlen.asm" - + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL - + __STRLEN: ; Direct FASTCALL entry ld a, h or l ret z - + ld a, (hl) inc hl ld h, (hl) ; LEN(str) in HL ld l, a ret - - + + #line 18 "strslice.asm" #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -562,25 +562,25 @@ __STRLEN: ; Direct FASTCALL entry ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -589,51 +589,51 @@ __STRLEN: ; Direct FASTCALL entry ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -641,12 +641,12 @@ __STRLEN: ; Direct FASTCALL entry ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -654,16 +654,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -675,27 +675,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -707,7 +707,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -715,15 +715,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -748,14 +748,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -763,41 +763,41 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 19 "strslice.asm" - - + + __STRSLICE: ; Callee entry pop hl ; Return ADDRESS pop bc ; Last char pos pop de ; 1st char pos ex (sp), hl ; CALLEE. -> String start - + __STRSLICE_FAST: ; __FASTCALL__ Entry PROC - + LOCAL __CONT LOCAL __EMPTY LOCAL __FREE_ON_EXIT - + push hl ; Stores original HL pointer to be recovered on exit ex af, af' ; Saves A register for later - + push hl call __STRLEN - inc bc ; Last character position + 1 (string starts from 0) + inc bc ; Last character position + 1 (string starts from 0) or a sbc hl, bc ; Compares length with last char position jr nc, __CONT ; If Carry => We must copy to end of string @@ -805,19 +805,19 @@ __STRSLICE_FAST: ; __FASTCALL__ Entry ld b, h ld c, l ; Copy to the end of str ccf ; Clears Carry flag for next subtraction - + __CONT: - ld h, b + ld h, b ld l, c ; HL = Last char position to copy (1 for char 0, 2 for char 1, etc) sbc hl, de ; HL = LEN(a$) - DE => Number of chars to copy jr z, __EMPTY ; 0 Chars to copy => Return HL = 0 (NULL STR) jr c, __EMPTY ; If Carry => Nothing to return (NULL STR) - + ld b, h ld c, l ; BC = Number of chars to copy inc bc inc bc ; +2 bytes for string length number - + push bc push de call __MEM_ALLOC @@ -826,15 +826,15 @@ __CONT: ld a, h or l jr z, __EMPTY ; Return if NULL (no memory) - + dec bc dec bc ; Number of chars to copy (Len of slice) - + ld (hl), c inc hl ld (hl), b inc hl ; Stores new string length - + ex (sp), hl ; Pointer to A$ now in HL; Pointer to new string chars in Stack inc hl inc hl ; Skip string length @@ -847,26 +847,26 @@ __CONT: dec de ; Points to String LEN start ex de, hl ; Returns it in HL jr __FREE_ON_EXIT - + __EMPTY: ; Return NULL (empty) string pop hl ld hl, 0 ; Return NULL - - + + __FREE_ON_EXIT: ex af, af' ; Recover original A register ex (sp), hl ; Original HL pointer - + or a call nz, __MEM_FREE - + pop hl ; Recover result - ret - - ENDP - + ret + + ENDP + #line 37 "strsigil.bas" - + ZXBASIC_USER_DATA: _e3: DEFB 00 diff --git a/tests/functional/sub16.asm b/tests/functional/sub16.asm index 2b632518c..e4d0a8338 100644 --- a/tests/functional/sub16.asm +++ b/tests/functional/sub16.asm @@ -46,7 +46,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/sub16a.asm b/tests/functional/sub16a.asm index 91493915c..a3dc1cc12 100644 --- a/tests/functional/sub16a.asm +++ b/tests/functional/sub16a.asm @@ -34,7 +34,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/sub16b.asm b/tests/functional/sub16b.asm index 134721fbc..c2f89948f 100644 --- a/tests/functional/sub16b.asm +++ b/tests/functional/sub16b.asm @@ -42,7 +42,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/sub8.asm b/tests/functional/sub8.asm index f81f9f9ed..3d64a8278 100644 --- a/tests/functional/sub8.asm +++ b/tests/functional/sub8.asm @@ -42,7 +42,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/sub8a.asm b/tests/functional/sub8a.asm index 410f62f65..71679c05b 100644 --- a/tests/functional/sub8a.asm +++ b/tests/functional/sub8a.asm @@ -32,7 +32,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/sub8b.asm b/tests/functional/sub8b.asm index f76121722..2397e2d7c 100644 --- a/tests/functional/sub8b.asm +++ b/tests/functional/sub8b.asm @@ -38,7 +38,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/tests/functional/subf00.asm b/tests/functional/subf00.asm index cabe1746e..648d39094 100644 --- a/tests/functional/subf00.asm +++ b/tests/functional/subf00.asm @@ -35,13 +35,13 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "pushf.asm" - - - ; Routine to push Float pointed by HL + + + ; Routine to push Float pointed by HL ; Into the stack. Notice that the hl points to the last ; byte of the FP number. ; Uses H'L' B'C' and D'E' to preserve ABCDEHL registers - + __FP_PUSH_REV: push hl exx @@ -62,11 +62,11 @@ __FP_PUSH_REV: push bc ; Return Address exx ret - - + + #line 26 "subf00.bas" #line 1 "storef.asm" - + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -74,7 +74,7 @@ __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory pop hl ; HL <- IX add hl, de ; HL <- IX + HL pop de - + __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register ex af, af' ld a, (hl) @@ -82,7 +82,7 @@ __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address ld h, (hl) ld l, a ; HL = (HL) ex af, af' - + __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), a inc hl @@ -94,43 +94,43 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL inc hl ld (hl), b ret - + #line 27 "subf00.bas" #line 1 "subf.asm" - + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -146,31 +146,31 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 2 "subf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) - + ; All of them uses A EDCB registers as 1st paramter. ; For binary operators, the 2n operator must be pushed into the ; stack, in the order A DE BC. ; ; Uses CALLEE convention ; ------------------------------------------------------------- - - + + __SUBF: ; Subtraction call __FPSTACK_PUSH2 ; ENTERS B, A - + ; ------------- ROM SUB rst 28h defb 01h ; EXCHANGE defb 03h ; SUB defb 38h; ; END CALC - + jp __FPSTACK_POP - + #line 28 "subf00.bas" - + ZXBASIC_USER_DATA: _a: DEFB 80h diff --git a/tests/functional/subf01.asm b/tests/functional/subf01.asm index 9f8af4a72..3d8eee9b9 100644 --- a/tests/functional/subf01.asm +++ b/tests/functional/subf01.asm @@ -39,7 +39,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "storef.asm" - + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -47,7 +47,7 @@ __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory pop hl ; HL <- IX add hl, de ; HL <- IX + HL pop de - + __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register ex af, af' ld a, (hl) @@ -55,7 +55,7 @@ __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address ld h, (hl) ld l, a ; HL = (HL) ex af, af' - + __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), a inc hl @@ -67,43 +67,43 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL inc hl ld (hl), b ret - + #line 30 "subf01.bas" #line 1 "subf.asm" - + #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -119,31 +119,31 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 2 "subf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) - + ; All of them uses A EDCB registers as 1st paramter. ; For binary operators, the 2n operator must be pushed into the ; stack, in the order A DE BC. ; ; Uses CALLEE convention ; ------------------------------------------------------------- - - + + __SUBF: ; Subtraction call __FPSTACK_PUSH2 ; ENTERS B, A - + ; ------------- ROM SUB rst 28h defb 01h ; EXCHANGE defb 03h ; SUB defb 38h; ; END CALC - + jp __FPSTACK_POP - + #line 31 "subf01.bas" - + ZXBASIC_USER_DATA: _a: DEFB 80h diff --git a/tests/functional/subf16c.asm b/tests/functional/subf16c.asm index 109ae9097..7efa8c38a 100644 --- a/tests/functional/subf16c.asm +++ b/tests/functional/subf16c.asm @@ -59,40 +59,40 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sub32.asm" - - ; SUB32 + + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) ; and returns result in DEHL. Carry an Z are set correctly - + __SUB32: exx pop bc ; saves return address in BC' exx - + or a ; clears carry flag ld b, h ; Operands come reversed => BC <- HL, HL = HL - BC ld c, l pop hl sbc hl, bc ex de, hl - + ld b, h ; High part (DE) now in HL. Repeat operation ld c, l pop hl sbc hl, bc ex de, hl ; DEHL now has de 32 bit result - + exx push bc ; puts return address back exx ret #line 50 "subf16c.bas" #line 1 "swap32.asm" - + ; Exchanges current DE HL with the ; ones in the stack - + __SWAP32: pop bc ; Return address ex (sp), hl @@ -105,9 +105,9 @@ __SWAP32: inc sp push bc ret - + #line 51 "subf16c.bas" - + ZXBASIC_USER_DATA: _level: DEFB 00h diff --git a/tests/functional/subi32c.asm b/tests/functional/subi32c.asm index 526185984..f30b79583 100644 --- a/tests/functional/subi32c.asm +++ b/tests/functional/subi32c.asm @@ -68,40 +68,40 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sub32.asm" - - ; SUB32 + + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) ; and returns result in DEHL. Carry an Z are set correctly - + __SUB32: exx pop bc ; saves return address in BC' exx - + or a ; clears carry flag ld b, h ; Operands come reversed => BC <- HL, HL = HL - BC ld c, l pop hl sbc hl, bc ex de, hl - + ld b, h ; High part (DE) now in HL. Repeat operation ld c, l pop hl sbc hl, bc ex de, hl ; DEHL now has de 32 bit result - + exx push bc ; puts return address back exx ret #line 59 "subi32c.bas" #line 1 "swap32.asm" - + ; Exchanges current DE HL with the ; ones in the stack - + __SWAP32: pop bc ; Return address ex (sp), hl @@ -114,9 +114,9 @@ __SWAP32: inc sp push bc ret - + #line 60 "subi32c.bas" - + ZXBASIC_USER_DATA: _level: DEFB 01h diff --git a/tests/functional/subparam.asm b/tests/functional/subparam.asm index e743019ca..7359b9357 100644 --- a/tests/functional/subparam.asm +++ b/tests/functional/subparam.asm @@ -46,7 +46,7 @@ _test__leave: ex (sp), hl exx ret - + ZXBASIC_USER_DATA: ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP diff --git a/tests/functional/substrlval.asm b/tests/functional/substrlval.asm index c1431b10d..248e9f3ac 100644 --- a/tests/functional/substrlval.asm +++ b/tests/functional/substrlval.asm @@ -58,21 +58,21 @@ __LABEL1: DEFW 0001h DEFB 7Ah #line 1 "letsubstr.asm" - + ; Substring assigment eg. LET a$(p0 TO p1) = "xxxx" ; HL = Start of string ; TOP of the stack -> p1 (16 bit, unsigned) - ; TOP -1 of the stack -> p0 register + ; TOP -1 of the stack -> p0 register ; TOP -2 Flag (popped out in A register) ; A Register => 0 if HL is not freed from memory ; => Not 0 if HL must be freed from memory on exit ; TOP -3 B$ address - + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -80,25 +80,25 @@ __LABEL1: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -107,41 +107,41 @@ __LABEL1: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -149,25 +149,25 @@ __LABEL1: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -176,39 +176,39 @@ __LABEL1: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -216,56 +216,56 @@ __LABEL1: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -274,57 +274,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -333,47 +333,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -383,92 +383,92 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 11 "letsubstr.asm" - + __LETSUBSTR: PROC - + LOCAL __CONT0 LOCAL __CONT1 LOCAL __CONT2 LOCAL __FREE_STR LOCAL __FREE_STR0 - + exx pop hl ; Return address pop de ; p1 pop bc ; p0 exx - + pop af ; Flag ex af, af' ; Save it for later - + pop de ; B$ - + exx push hl ; push ret addr back exx - + ld a, h or l jp z, __FREE_STR0 ; Return if null - + ld c, (hl) inc hl ld b, (hl) ; BC = Str length inc hl ; HL = String start push bc - + exx ex de, hl or a sbc hl, bc ; HL = Length of string requester by user inc hl ; len (a$(p0 TO p1)) = p1 - p0 + 1 ex de, hl ; Saves it in DE - + pop hl ; HL = String length exx jp c, __FREE_STR0 ; Return if greather exx ; Return if p0 > p1 - + or a sbc hl, bc ; P0 >= String length? exx - + jp z, __FREE_STR0 ; Return if equal jp c, __FREE_STR0 ; Return if greather - + exx add hl, bc ; Add it back - + sbc hl, de ; Length of substring > string => Truncate it add hl, de ; add it back jr nc, __CONT0 ; Length of substring within a$ - + ld d, h ld e, l ; Truncate length of substring to fit within the strlen - + __CONT0: ; At this point DE = Length of subtring to copy ; BC = start of char to copy push de - + push bc exx pop bc - + add hl, bc ; Start address (within a$) so copy from b$ (in DE) - + push hl exx pop hl ; Start address (within a$) so copy from b$ (in DE) - + ld b, d ; Length of string ld c, e - - ld (hl), ' ' + + ld (hl), ' ' ld d, h ld e, l inc de @@ -476,33 +476,33 @@ __CONT0: ; At this point DE = Length of subtring to copy ld a, b or c jr z, __CONT2 - + ; At this point HL = DE = Start of Write zone in a$ ; BC = Number of chars to write - + ldir - + __CONT2: - + pop bc ; Recovers Length of string to copy exx ex de, hl ; HL = Source, DE = Target - + ld a, h or l jp z, __FREE_STR ; Return if B$ is NULL - + ld c, (hl) inc hl ld b, (hl) inc hl - + ld a, b or c jp z, __FREE_STR ; Return if len(b$) = 0 - + ; Now if len(b$) < len(char to copy), copy only len(b$) chars - + push de push hl push bc @@ -512,38 +512,38 @@ __CONT2: sbc hl, bc add hl, bc jr nc, __CONT1 - + ; If len(b$) < len(to copy) ld b, h ; BC = len(to copy) ld c, l - + __CONT1: - pop hl + pop hl pop de ldir ; Copy b$ into a$(x to y) - + exx ex de, hl - + __FREE_STR0: ex de, hl - + __FREE_STR: ex af, af' - or a ; If not 0, free + or a ; If not 0, free jp nz, __MEM_FREE ret - + ENDP - + #line 46 "substrlval.bas" #line 1 "loadstr.asm" - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -551,25 +551,25 @@ __FREE_STR: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -578,51 +578,51 @@ __FREE_STR: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -630,12 +630,12 @@ __FREE_STR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -643,16 +643,16 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 69 "alloc.asm" - - - + + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -664,27 +664,27 @@ __STOP: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -696,7 +696,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -704,15 +704,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -737,14 +737,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -752,25 +752,25 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 2 "loadstr.asm" - + ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again ; Finally, it returns result pointer in HL - + __ILOADSTR: ; This is the indirect pointer entry HL = (HL) ld a, h or l @@ -779,30 +779,30 @@ __ILOADSTR: ; This is the indirect pointer entry HL = (HL) inc hl ld h, (hl) ld l, a - + __LOADSTR: ; __FASTCALL__ entry ld a, h or l ret z ; Return if NULL - + ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(a$) - + inc bc inc bc ; BC = LEN(a$) + 2 (two bytes for length) - + push hl push bc call __MEM_ALLOC pop bc ; Recover length pop de ; Recover origin - + ld a, h or l ret z ; Return if NULL (No memory) - + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE push de ; Saves destiny start ldir ; Copies string (length number included) @@ -810,7 +810,7 @@ __LOADSTR: ; __FASTCALL__ entry ret #line 47 "substrlval.bas" #line 1 "storestr.asm" - + ; vim:ts=4:et:sw=4 ; Stores value of current string pointed by DE register into address pointed by HL ; Returns DE = Address pointer (&a$) @@ -821,15 +821,15 @@ __LOADSTR: ; __FASTCALL__ entry ; ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ - - + + #line 1 "strcpy.asm" - + #line 1 "realloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -837,25 +837,25 @@ __LOADSTR: ; __FASTCALL__ entry ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -864,42 +864,42 @@ __LOADSTR: ; __FASTCALL__ entry ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - - - - + + + + + + + ; --------------------------------------------------------------------- ; MEM_REALLOC ; Reallocates a block of memory in the heap. @@ -918,29 +918,29 @@ __LOADSTR: ; __FASTCALL__ entry ; the new size is adjusted. If BC < original length, the content ; will be truncated. Otherwise, extra block content might contain ; memory garbage. - ; + ; ; --------------------------------------------------------------------- __REALLOC: ; Reallocates block pointed by HL, with new length BC PROC - + LOCAL __REALLOC_END - + ld a, h or l jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc - + ld e, (hl) inc hl ld d, (hl) ; DE = First 2 bytes of HL block - + push hl exx pop de inc de ; DE' <- HL + 2 exx ; DE' <- HL (Saves current pointer into DE') - + dec hl ; HL = Block start - + push de push bc call __MEM_FREE ; Frees current block @@ -949,111 +949,111 @@ __REALLOC: ; Reallocates block pointed by HL, with new length BC call __MEM_ALLOC ; Gets a new block of length BC pop bc pop de - + ld a, h or l ret z ; Return if HL == NULL (No memory) - + ld (hl), e inc hl ld (hl), d inc hl ; Recovers first 2 bytes in HL - + dec bc dec bc ; BC = BC - 2 (Two bytes copied) - + ld a, b or c jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) - + exx push de exx pop de ; DE <- DE' ; Start of remaining block - + push hl ; Saves current Block + 2 start ex de, hl ; Exchanges them: DE is destiny block ldir ; Copies BC Bytes pop hl ; Recovers Block + 2 start - + __REALLOC_END: - + dec hl ; Set HL dec hl ; To begin of block ret - + ENDP - + #line 2 "strcpy.asm" - + ; String library - - + + __STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) PROC - + LOCAL __STRREALLOC LOCAL __STRCONTINUE LOCAL __B_IS_NULL LOCAL __NOTHING_TO_COPY - + ld b, d ld c, e ld a, b or c jr z, __B_IS_NULL - + ex de, hl ld c, (hl) inc hl ld b, (hl) dec hl ; BC = LEN(b$) ex de, hl ; DE = &b$ - + __B_IS_NULL: ; Jumps here if B$ pointer is NULL inc bc inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) - + push de push hl - + ld a, h or l jr z, __STRREALLOC - + dec hl ld d, (hl) dec hl ld e, (hl) ; DE = MEMBLOCKSIZE(a$) dec de dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) - + ld h, b ld l, c ; HL = LEN(b$) + 2 => Minimum block size required ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 - + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) sbc hl, de ; Carry if len(b$) > Blocklen(a$) jr c, __STRREALLOC ; No need to realloc ; Need to reallocate at least to len(b$) + 2 ex de, hl ; DE = Remaining bytes in a$ mem block. - ld hl, 4 + ld hl, 4 sbc hl, de ; if remaining bytes < 4 we can continue jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes - + __STRREALLOC: pop hl call __REALLOC ; Returns in HL a new pointer with BC bytes allocated - push hl - + push hl + __STRCONTINUE: ; Pops hl and de SWAPPED pop de ; DE = &a$ pop hl ; HL = &b$ - + ld a, d ; Return if not enough memory for new length or e ret z ; Return if DE == NULL (0) - + __STRCPY: ; Copies string pointed by HL into string pointed by DE ; Returns DE as HL (new pointer) ld a, h @@ -1069,7 +1069,7 @@ __STRCPY: ; Copies string pointed by HL into string pointed by DE ldir pop hl ret - + __NOTHING_TO_COPY: ex de, hl ld (hl), e @@ -1077,44 +1077,44 @@ __NOTHING_TO_COPY: ld (hl), d dec hl ret - + ENDP - + #line 14 "storestr.asm" - + __PISTORE_STR: ; Indirect assignement at (IX + BC) push ix pop hl add hl, bc - + __ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + __STORE_STR: push de ; Pointer to b$ push hl ; Array pointer to variable memory address - + ld c, (hl) inc hl ld h, (hl) ld l, c ; HL = (HL) - + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation ex de, hl ; DE = new address of a$ pop hl ; Recover variable memory address pointer - + ld (hl), e inc hl ld (hl), d ; Stores a$ ptr into elemem ptr - + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) ret - + #line 48 "substrlval.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/subu32c.asm b/tests/functional/subu32c.asm index ba654bcb5..3c66baa6a 100644 --- a/tests/functional/subu32c.asm +++ b/tests/functional/subu32c.asm @@ -68,40 +68,40 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "sub32.asm" - - ; SUB32 + + ; SUB32 ; Perform TOP of the stack - DEHL ; Pops operand out of the stack (CALLEE) ; and returns result in DEHL. Carry an Z are set correctly - + __SUB32: exx pop bc ; saves return address in BC' exx - + or a ; clears carry flag ld b, h ; Operands come reversed => BC <- HL, HL = HL - BC ld c, l pop hl sbc hl, bc ex de, hl - + ld b, h ; High part (DE) now in HL. Repeat operation ld c, l pop hl sbc hl, bc ex de, hl ; DEHL now has de 32 bit result - + exx push bc ; puts return address back exx ret #line 59 "subu32c.bas" #line 1 "swap32.asm" - + ; Exchanges current DE HL with the ; ones in the stack - + __SWAP32: pop bc ; Return address ex (sp), hl @@ -114,9 +114,9 @@ __SWAP32: inc sp push bc ret - + #line 60 "subu32c.bas" - + ZXBASIC_USER_DATA: _level: DEFB 01h diff --git a/tests/functional/usr0.asm b/tests/functional/usr0.asm index 02b31a4f5..4bd61fcd1 100644 --- a/tests/functional/usr0.asm +++ b/tests/functional/usr0.asm @@ -39,17 +39,17 @@ __LABEL0: DEFW 0001h DEFB 41h #line 1 "print.asm" - + ; vim:ts=4:sw=4:et: ; PRINT command routine ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that - + #line 1 "sposn.asm" - + ; Printing positioning library. PROC - LOCAL ECHO_E - + LOCAL ECHO_E + __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. ld de, (S_POSN) ld hl, (MAXX) @@ -57,46 +57,46 @@ __LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem sbc hl, de ex de, hl ret - - + + __SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. ld hl, (MAXX) or a sbc hl, de ld (S_POSN), hl ; saves it again ret - - + + ECHO_E EQU 23682 MAXX EQU ECHO_E ; Max X position + 1 MAXY EQU MAXX + 1 ; Max Y position + 1 - - S_POSN EQU 23688 + + S_POSN EQU 23688 POSX EQU S_POSN ; Current POS X POSY EQU S_POSN + 1 ; Current POS Y - + ENDP - + #line 6 "print.asm" #line 1 "cls.asm" - + ; JUMPS directly to spectrum CLS ; This routine does not clear lower screen - + ;CLS EQU 0DAFh - + ; Our faster implementation - - - + + + CLS: PROC - + LOCAL COORDS LOCAL __CLS_SCR LOCAL ATTR_P LOCAL SCREEN - + ld hl, 0 ld (COORDS), hl ld hl, 1821h @@ -109,43 +109,43 @@ __CLS_SCR: inc de ld bc, 6144 ldir - + ; Now clear attributes - + ld a, (ATTR_P) ld (hl), a ld bc, 767 ldir ret - + COORDS EQU 23677 SCREEN EQU 16384 ; Default start of the screen (can be changed) ATTR_P EQU 23693 ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address - + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines ; to get the start of the screen ENDP - + #line 7 "print.asm" #line 1 "in_screen.asm" - - + + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -153,12 +153,12 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -166,51 +166,51 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: ld (ERR_NR), a ret #line 3 "in_screen.asm" - + __IN_SCREEN: ; Returns NO carry if current coords (D, E) ; are OUT of the screen limits (MAXX, MAXY) - + PROC LOCAL __IN_SCREEN_ERR - + ld hl, MAXX ld a, e cp (hl) jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range - + ld a, d inc hl cp (hl) ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range ;; ret ret c ; Return if carry (OK) - + __IN_SCREEN_ERR: __OUT_OF_SCREEN_ERR: ; Jumps here if out of screen ld a, ERROR_OutOfScreen jp __STOP ; Saves error code and exits - + ENDP #line 8 "print.asm" #line 1 "table_jump.asm" - - + + JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A add a, a - + JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE ld e, a ld d, 0 - + JUMP_HL_PLUS_DE: ; Does JP (HL + DE) add hl, de ld e, (hl) @@ -219,17 +219,17 @@ JUMP_HL_PLUS_DE: ; Does JP (HL + DE) ex de, hl CALL_HL: jp (hl) - + #line 9 "print.asm" #line 1 "ink.asm" - + ; Sets ink color in ATTR_P permanently ; Parameter: Paper color in A register - + #line 1 "const.asm" - + ; Global constants - + P_FLAG EQU 23697 FLAGS2 EQU 23681 ATTR_P EQU 23693 ; permanet ATTRIBUTES @@ -237,26 +237,26 @@ CALL_HL: CHARS EQU 23606 ; Pointer to ROM/RAM Charset UDG EQU 23675 ; Pointer to UDG Charset MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars - + #line 5 "ink.asm" - + INK: PROC LOCAL __SET_INK LOCAL __SET_INK2 - + ld de, ATTR_P - + __SET_INK: cp 8 jr nz, __SET_INK2 - + inc de ; Points DE to MASK_T or MASK_P ld a, (de) or 7 ; Set bits 0,1,2 to enable transparency ld (de), a ret - + __SET_INK2: ; Another entry. This will set the ink color at location pointer by DE and 7 ; # Gets color mod 8 @@ -270,45 +270,45 @@ __SET_INK2: and 0F8h ; Reset bits 0,1,2 sign to disable transparency ld (de), a ; Store new attr ret - + ; Sets the INK color passed in A register in the ATTR_T variable INK_TMP: ld de, ATTR_T jp __SET_INK - + ENDP - + #line 10 "print.asm" #line 1 "paper.asm" - + ; Sets paper color in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + PAPER: PROC LOCAL __SET_PAPER LOCAL __SET_PAPER2 - + ld de, ATTR_P - + __SET_PAPER: - cp 8 + cp 8 jr nz, __SET_PAPER2 inc de ld a, (de) or 038h ld (de), a ret - + ; Another entry. This will set the paper color at location pointer by DE __SET_PAPER2: - and 7 ; # Remove + and 7 ; # Remove rlca rlca rlca ; a *= 8 - + ld b, a ; Saves the color ld a, (de) and 0C7h ; Clears previous value @@ -319,28 +319,28 @@ __SET_PAPER2: and 0C7h ; Resets bits 3,4,5 ld (de), a ret - - + + ; Sets the PAPER color passed in A register in the ATTR_T variable PAPER_TMP: ld de, ATTR_T jp __SET_PAPER ENDP - + #line 11 "print.asm" #line 1 "flash.asm" - + ; Sets flash flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + FLASH: ld de, ATTR_P __SET_FLASH: ; Another entry. This will set the flash flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca ld b, a ; Saves the color ld a, (de) @@ -348,28 +348,28 @@ __SET_FLASH: or b ld (de), a ret - - + + ; Sets the FLASH flag passed in A register in the ATTR_T variable FLASH_TMP: ld de, ATTR_T jr __SET_FLASH - + #line 12 "print.asm" #line 1 "bright.asm" - + ; Sets bright flag in ATTR_P permanently ; Parameter: Paper color in A register - - - + + + BRIGHT: ld de, ATTR_P - + __SET_BRIGHT: ; Another entry. This will set the bright flag at location pointer by DE and 1 ; # Convert to 0/1 - + rrca rrca ld b, a ; Saves the color @@ -378,83 +378,83 @@ __SET_BRIGHT: or b ld (de), a ret - - + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable BRIGHT_TMP: ld de, ATTR_T jr __SET_BRIGHT - + #line 13 "print.asm" #line 1 "over.asm" - + ; Sets OVER flag in P_FLAG permanently ; Parameter: OVER flag in bit 0 of A register #line 1 "copy_attr.asm" - - - + + + #line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" - - - + + + COPY_ATTR: ; Just copies current permanent attribs to temporal attribs - ; and sets print mode + ; and sets print mode PROC - + LOCAL INVERSE1 LOCAL __REFRESH_TMP - + INVERSE1 EQU 02Fh - + ld hl, (ATTR_P) ld (ATTR_T), hl - + ld hl, FLAGS2 call __REFRESH_TMP - + ld hl, P_FLAG call __REFRESH_TMP - - + + __SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) - - - LOCAL TABLE + + + LOCAL TABLE LOCAL CONT2 - + rra ; Over bit to carry ld a, (FLAGS2) rla ; Over bit in bit 1, Over2 bit in bit 2 and 3 ; Only bit 0 and 1 (OVER flag) - + ld c, a ld b, 0 - + ld hl, TABLE add hl, bc ld a, (hl) ld (PRINT_MODE), a - + ld hl, (P_FLAG) xor a ; NOP -> INVERSE0 bit 2, l jr z, CONT2 ld a, INVERSE1 ; CPL -> INVERSE1 - + CONT2: ld (INVERSE_MODE), a ret - + TABLE: nop ; NORMAL MODE xor (hl) ; OVER 1 MODE and (hl) ; OVER 2 MODE - or (hl) ; OVER 3 MODE - + or (hl) ; OVER 3 MODE + #line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" - + __REFRESH_TMP: ld a, (hl) and 10101010b @@ -463,32 +463,32 @@ __REFRESH_TMP: or c ld (hl), a ret - + ENDP - + #line 4 "over.asm" - - + + OVER: PROC - + ld c, a ; saves it for later and 2 ld hl, FLAGS2 res 1, (HL) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ; # Convert to 0/1 add a, a; # Shift left 1 bit for permanent - + ld hl, P_FLAG res 1, (hl) or (hl) ld (hl), a ret - + ; Sets OVER flag in P_FLAG temporarily OVER_TMP: ld c, a ; saves it for later @@ -498,7 +498,7 @@ OVER_TMP: res 0, (hl) or (hl) ld (hl), a - + ld a, c ; Recovers previous value and 1 ld hl, P_FLAG @@ -506,20 +506,20 @@ OVER_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 14 "print.asm" #line 1 "inverse.asm" - + ; Sets INVERSE flag in P_FLAG permanently ; Parameter: INVERSE flag in bit 0 of A register - - - + + + INVERSE: PROC - + and 1 ; # Convert to 0/1 add a, a; # Shift left 3 bits for permanent add a, a @@ -529,7 +529,7 @@ INVERSE: or (hl) ld (hl), a ret - + ; Sets INVERSE flag in P_FLAG temporarily INVERSE_TMP: and 1 @@ -540,19 +540,19 @@ INVERSE_TMP: or (hl) ld (hl), a jp __SET_ATTR_MODE - + ENDP - + #line 15 "print.asm" #line 1 "bold.asm" - + ; Sets BOLD flag in P_FLAG permanently ; Parameter: BOLD flag in bit 0 of A register - - + + BOLD: PROC - + and 1 rlca rlca @@ -562,7 +562,7 @@ BOLD: or (hl) ld (hl), a ret - + ; Sets BOLD flag in P_FLAG temporarily BOLD_TMP: and 1 @@ -573,19 +573,19 @@ BOLD_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 16 "print.asm" #line 1 "italic.asm" - + ; Sets ITALIC flag in P_FLAG permanently ; Parameter: ITALIC flag in bit 0 of A register - - + + ITALIC: PROC - + and 1 rrca rrca @@ -595,7 +595,7 @@ ITALIC: or (hl) ld (hl), a ret - + ; Sets ITALIC flag in P_FLAG temporarily ITALIC_TMP: and 1 @@ -608,22 +608,22 @@ ITALIC_TMP: or (hl) ld (hl), a ret - + ENDP - + #line 17 "print.asm" - + #line 1 "attr.asm" - + ; Attribute routines ; vim:ts=4:et:sw: - - - - - - - + + + + + + + __ATTR_ADDR: ; calc start address in DE (as (32 * d) + e) ; Contributed by Santiago Romero at http://www.speccy.org @@ -632,79 +632,79 @@ __ATTR_ADDR: add a, a ; a * 2 ; 4 T-States add a, a ; a * 4 ; 4 T-States ld l, a ; HL = A * 4 ; 4 T-States - + add hl, hl ; HL = A * 8 ; 15 T-States add hl, hl ; HL = A * 16 ; 15 T-States add hl, hl ; HL = A * 32 ; 15 T-States - + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) add hl, de - + ld de, (SCREEN_ADDR) ; Adds the screen address add hl, de - + ; Return current screen address in HL ret - - + + ; Sets the attribute at a given screen coordinate (D, E). ; The attribute is taken from the ATTR_T memory variable ; Used by PRINT routines SET_ATTR: - + ; Checks for valid coords call __IN_SCREEN ret nc - + __SET_ATTR: ; Internal __FASTCALL__ Entry used by printing routines - PROC - + PROC + call __ATTR_ADDR ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T - + ld a, d and (hl) ld c, a ; C = current screen color, masked - + ld a, d cpl ; Negate mask and e ; Mask current attributes or c ; Mix them ld (hl), a ; Store result in screen - + ret - + ENDP - - + + #line 19 "print.asm" - - ; Putting a comment starting with @INIT
+ + ; Putting a comment starting with @INIT
; will make the compiler to add a CALL to
; It is useful for initialization routines. - - + + __PRINT_INIT: ; To be called before program starts (initializes library) PROC - + ld hl, __PRINT_START ld (PRINT_JUMP_STATE), hl - + ld hl, 1821h ld (MAXX), hl ; Sets current maxX and maxY - + xor a ld (FLAGS2), a - + ret - - + + __PRINTCHAR: ; Print character store in accumulator (A register) ; Modifies H'L', B'C', A'F', D'E', A - + LOCAL PO_GR_1 - + LOCAL __PRCHAR LOCAL __PRINT_CONT LOCAL __PRINT_CONT2 @@ -713,75 +713,75 @@ __PRINTCHAR: ; Print character store in accumulator (A register) LOCAL __PRINT_UDG LOCAL __PRGRAPH LOCAL __PRINT_START - + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 - + __PRINT_JUMP: jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively - + __PRINT_START: cp ' ' jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones - + exx ; Switch to alternative registers ex af, af' ; Saves a value (char to print) for later - + call __LOAD_S_POSN - + ; At this point we have the new coord ld hl, (SCREEN_ADDR) - + ld a, d ld c, a ; Saves it for later - + and 0F8h ; Masks 3 lower bit ; zy ld d, a - + ld a, c ; Recovers it and 07h ; MOD 7 ; y1 rrca rrca rrca - + or e ld e, a add hl, de ; HL = Screen address + DE ex de, hl ; DE = Screen address - + ex af, af' - - cp 80h ; Is it an UDG or a ? + + cp 80h ; Is it an UDG or a ? jp c, __SRCADDR - + cp 90h jp nc, __PRINT_UDG - + ; Print a 8 bit pattern (80h to 8Fh) - + ld b, a call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 ld hl, MEM0 jp __PRGRAPH - + PO_GR_1 EQU 0B38h - + __PRINT_UDG: sub 90h ; Sub ASC code ld bc, (UDG) jp __PRGRAPH0 - + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source __SRCADDR: ld bc, (CHARS) - + __PRGRAPH0: add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org ld l, a ld h, 0 ; HL = a * 2 (accumulator) - add hl, hl + add hl, hl add hl, hl ; HL = a * 8 add hl, bc ; HL = CHARS address - + __PRGRAPH: ex de, hl ; HL = Write Address, DE = CHARS address bit 2, (iy + $47) @@ -791,7 +791,7 @@ __PRGRAPH: ld b, 8 ; 8 bytes per char __PRCHAR: ld a, (de) ; DE *must* be ALWAYS source, and HL destiny - + PRINT_MODE: ; Which operation is used to write on the screen ; Set it with: ; LD A, @@ -803,16 +803,16 @@ PRINT_MODE: ; Which operation is used to write on the screen ; OR : B6h --> OR (HL) ; PUTSPRITE ; AND : A6h --> AND (HL) ; PUTMASK nop ; - + INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 nop ; 2F -> CPL -> INVERSE 1 - + ld (hl), a - - inc de + + inc de inc h ; Next line - djnz __PRCHAR - + djnz __PRCHAR + call __LOAD_S_POSN push de call __SET_ATTR @@ -826,49 +826,49 @@ INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 call __PRINT_EOL1 exx ; counteracts __PRINT_EOL1 exx jp __PRINT_CONT2 - + __PRINT_CONT: call __SAVE_S_POSN - + __PRINT_CONT2: exx ret - + ; ------------- SPECIAL CHARS (< 32) ----------------- - + __PRINT_SPECIAL: ; Jumps here if it is a special char exx ld hl, __PRINT_TABLE jp JUMP_HL_PLUS_2A - - + + PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence exx - + __PRINT_0Dh: ; Called WHEN printing CHR$(13) call __LOAD_S_POSN - + __PRINT_EOL1: ; Another entry called from PRINT when next line required ld e, 0 - + __PRINT_EOL2: ld a, d inc a - + __PRINT_AT1_END: ld hl, (MAXY) cp l jr c, __PRINT_EOL_END ; Carry if (MAXY) < d xor a - + __PRINT_EOL_END: - ld d, a - + ld d, a + __PRINT_AT2_END: call __SAVE_S_POSN exx ret - + __PRINT_COM: exx push hl @@ -879,17 +879,17 @@ __PRINT_COM: pop de pop hl ret - + __PRINT_TAB: ld hl, __PRINT_TAB1 jp __PRINT_SET_STATE - + __PRINT_TAB1: - ld (MEM0), a + ld (MEM0), a ld hl, __PRINT_TAB2 ld (PRINT_JUMP_STATE), hl ret - + __PRINT_TAB2: ld a, (MEM0) ; Load tab code (ignore the current one) push hl @@ -902,27 +902,27 @@ __PRINT_TAB2: pop de pop hl ret - + __PRINT_NOP: __PRINT_RESTART: ld hl, __PRINT_START jp __PRINT_SET_STATE - + __PRINT_AT: ld hl, __PRINT_AT1 - + __PRINT_SET_STATE: ld (PRINT_JUMP_STATE), hl ; Saves next entry call exx ret - + __PRINT_AT1: ; Jumps here if waiting for 1st parameter exx ld hl, __PRINT_AT2 ld (PRINT_JUMP_STATE), hl ; Saves next entry call call __LOAD_S_POSN jp __PRINT_AT1_END - + __PRINT_AT2: exx ld hl, __PRINT_START @@ -930,10 +930,10 @@ __PRINT_AT2: call __LOAD_S_POSN ld e, a ld hl, (MAXX) - cp (hl) + cp (hl) jr c, __PRINT_AT2_END jr __PRINT_EOL1 - + __PRINT_DEL: call __LOAD_S_POSN ; Gets current screen position dec e @@ -950,80 +950,80 @@ __PRINT_DEL: ld d, h dec d jp __PRINT_AT2_END - + __PRINT_INK: ld hl, __PRINT_INK2 jp __PRINT_SET_STATE - + __PRINT_INK2: exx call INK_TMP jp __PRINT_RESTART - + __PRINT_PAP: ld hl, __PRINT_PAP2 jp __PRINT_SET_STATE - + __PRINT_PAP2: exx call PAPER_TMP jp __PRINT_RESTART - + __PRINT_FLA: ld hl, __PRINT_FLA2 jp __PRINT_SET_STATE - + __PRINT_FLA2: exx call FLASH_TMP jp __PRINT_RESTART - + __PRINT_BRI: ld hl, __PRINT_BRI2 jp __PRINT_SET_STATE - + __PRINT_BRI2: exx call BRIGHT_TMP jp __PRINT_RESTART - + __PRINT_INV: ld hl, __PRINT_INV2 jp __PRINT_SET_STATE - + __PRINT_INV2: exx call INVERSE_TMP jp __PRINT_RESTART - + __PRINT_OVR: ld hl, __PRINT_OVR2 jp __PRINT_SET_STATE - + __PRINT_OVR2: exx call OVER_TMP jp __PRINT_RESTART - + __PRINT_BOLD: ld hl, __PRINT_BOLD2 jp __PRINT_SET_STATE - + __PRINT_BOLD2: exx call BOLD_TMP jp __PRINT_RESTART - + __PRINT_ITA: ld hl, __PRINT_ITA2 jp __PRINT_SET_STATE - + __PRINT_ITA2: exx call ITALIC_TMP jp __PRINT_RESTART - - + + __BOLD: push hl ld hl, MEM0 @@ -1040,8 +1040,8 @@ __BOLD_LOOP: pop hl ld de, MEM0 ret - - + + __ITALIC: push hl ld hl, MEM0 @@ -1065,17 +1065,17 @@ __ITALIC: pop hl ld de, MEM0 ret - + PRINT_COMMA: call __LOAD_S_POSN ld a, e and 16 add a, 16 - + PRINT_TAB: PROC LOCAL LOOP, CONTINUE - + inc a call __LOAD_S_POSN ; e = current row ld d, a @@ -1086,7 +1086,7 @@ PRINT_TAB: CONTINUE: ld a, d inc e - sub e ; A = A - E + sub e ; A = A - E and 31 ; ret z ; Already at position E ld b, a @@ -1096,21 +1096,21 @@ LOOP: djnz LOOP ret ENDP - + PRINT_AT: ; CHanges cursor to ROW, COL ; COL in A register - ; ROW in stack - + ; ROW in stack + pop hl ; Ret address ex (sp), hl ; callee H = ROW ld l, a ex de, hl - + call __IN_SCREEN ret nc ; Return if out of screen - + jp __SAVE_S_POSN - + LOCAL __PRINT_COM LOCAL __BOLD LOCAL __BOLD_LOOP @@ -1129,9 +1129,9 @@ PRINT_AT: ; CHanges cursor to ROW, COL LOCAL __PRINT_SET_STATE LOCAL __PRINT_TABLE LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 - + __PRINT_TABLE: ; Jump table for 0 .. 22 codes - + DW __PRINT_NOP ; 0 DW __PRINT_NOP ; 1 DW __PRINT_NOP ; 2 @@ -1156,33 +1156,33 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes DW __PRINT_OVR ; 21 DW __PRINT_AT ; 22 AT DW __PRINT_TAB ; 23 TAB - + ENDP - - + + #line 26 "usr0.bas" #line 1 "printu16.asm" - + #line 1 "printi16.asm" - + #line 1 "printnum.asm" - - - - + + + + __PRINTU_START: PROC - + LOCAL __PRINTU_CONT - + ld a, b or a jp nz, __PRINTU_CONT - + ld a, '0' jp __PRINT_DIGIT - - + + __PRINTU_CONT: pop af push bc @@ -1190,30 +1190,30 @@ __PRINTU_CONT: pop bc djnz __PRINTU_CONT ret - + ENDP - - + + __PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers ld a, '-' jp __PRINT_DIGIT - + __PRINT_DIGIT EQU __PRINTCHAR ; PRINTS the char in A register, and puts its attrs - - + + #line 2 "printi16.asm" #line 1 "div16.asm" - - ; 16 bit division and modulo functions + + ; 16 bit division and modulo functions ; for both signed and unsigned values - + #line 1 "neg16.asm" - + ; Negates HL value (16 bit) __ABS16: bit 7, h ret z - + __NEGHL: ld a, l ; HL = -HL cpl @@ -1223,23 +1223,23 @@ __NEGHL: ld h, a inc hl ret - + #line 5 "div16.asm" - + __DIVU16: ; 16 bit unsigned division ; HL = Dividend, Stack Top = Divisor - + ; -- OBSOLETE ; Now uses FASTCALL convention ; ex de, hl ; pop hl ; Return address ; ex (sp), hl ; CALLEE Convention - + __DIVU16_FAST: ld a, h ld c, l ld hl, 0 ld b, 16 - + __DIV16LOOP: sll c rla @@ -1248,46 +1248,46 @@ __DIV16LOOP: jr nc, __DIV16NOADD add hl,de dec c - + __DIV16NOADD: djnz __DIV16LOOP - + ex de, hl ld h, a ld l, c - + ret ; HL = quotient, DE = Mudulus - - - + + + __MODU16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVU16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - - + + __DIVI16: ; 16 bit signed division ; --- The following is OBSOLETE --- ; ex de, hl ; pop hl ; ex (sp), hl ; CALLEE Convention - + __DIVI16_FAST: ld a, d xor h ex af, af' ; BIT 7 of a contains result - + bit 7, d ; DE is negative? - jr z, __DIVI16A - + jr z, __DIVI16A + ld a, e ; DE = -DE cpl ld e, a @@ -1295,90 +1295,90 @@ __DIVI16_FAST: cpl ld d, a inc de - + __DIVI16A: bit 7, h ; HL is negative? call nz, __NEGHL - + __DIVI16B: call __DIVU16_FAST ex af, af' - - or a + + or a ret p ; return if positive jp __NEGHL - - + + __MODI16: ; 16 bit modulus ; HL = Dividend, Stack Top = Divisor - + ;ex de, hl ;pop hl ;ex (sp), hl ; CALLEE Convention - + call __DIVI16_FAST ex de, hl ; hl = reminder (modulus) ; de = quotient - + ret - + #line 3 "printi16.asm" - - - + + + __PRINTI16: ; Prints a 16bits signed in HL ; Converts 16 to 32 bits PROC - + LOCAL __PRINTU_LOOP ld a, h or a - + jp p, __PRINTU16 - + call __PRINT_MINUS call __NEGHL - + __PRINTU16: - + ld b, 0 __PRINTU_LOOP: ld a, h or l jp z, __PRINTU_START - + push bc ld de, 10 call __DIVU16_FAST ; Divides by DE. DE = MODULUS at exit. Since < 256, E = Modulus pop bc - + ld a, e or '0' ; Stores ASCII digit (must be print in reversed order) push af inc b jp __PRINTU_LOOP ; Uses JP in loops - + ENDP - + #line 2 "printu16.asm" - + #line 27 "usr0.bas" #line 1 "usr_str.asm" - + ; This function just returns the address of the UDG of the given str. ; If the str is EMPTY or not a letter, 0 is returned and ERR_NR set ; to "A: Invalid Argument" - + ; On entry HL points to the string ; and A register is non-zero if the string must be freed (TMP string) - - - + + + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1386,25 +1386,25 @@ __PRINTU_LOOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1413,41 +1413,41 @@ __PRINTU_LOOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -1455,25 +1455,25 @@ __PRINTU_LOOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -1482,39 +1482,39 @@ __PRINTU_LOOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -1522,56 +1522,56 @@ __PRINTU_LOOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 69 "free.asm" - + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -1580,57 +1580,57 @@ __MEM_INIT2: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -1639,47 +1639,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -1689,27 +1689,27 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 11 "usr_str.asm" - + USR_STR: ex af, af' ; Saves A flag - + ld a, h or l jr z, USR_ERROR ; a$ = NULL => Invalid Arg - + ld d, h ; Saves HL in DE, for ld e, l ; later usage - + ld c, (hl) inc hl ld a, (hl) or c jr z, USR_ERROR ; a$ = "" => Invalid Arg - + inc hl ld a, (hl) ; Only the 1st char is needed and 11011111b ; Convert it to UPPER CASE @@ -1721,31 +1721,31 @@ USR_STR: add hl, hl ; hl = A * 8 ld bc, (UDG) add hl, bc - + ;; Now checks if the string must be released ex af, af' ; Recovers A flag or a ret z ; return if not - + push hl ; saves result since __MEM_FREE changes HL ex de, hl ; Recovers original HL value call __MEM_FREE pop hl ret - + USR_ERROR: ex de, hl ; Recovers original HL value ex af, af' ; Recovers A flag or a call nz, __MEM_FREE - + ld a, ERROR_InvalidArg ld (ERR_NR), a ld hl, 0 ret - + #line 28 "usr0.bas" - + ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: ; Defines DATA END diff --git a/tests/functional/valcrash2.asm b/tests/functional/valcrash2.asm index b3b469c8f..7b2cfe4f6 100644 --- a/tests/functional/valcrash2.asm +++ b/tests/functional/valcrash2.asm @@ -47,17 +47,17 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "inkey.asm" - + ; INKEY Function ; Returns a string allocated in dynamic memory ; containing the string. ; An empty string otherwise. - + #line 1 "alloc.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -65,25 +65,25 @@ __CALL_BACK__: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -92,51 +92,51 @@ __CALL_BACK__: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be freed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - + #line 1 "error.asm" - + ; Simple error control routines ; vim:ts=4:et: - + ERR_NR EQU 23610 ; Error code system variable - - + + ; Error code definitions (as in ZX spectrum manual) - + ; Set error code with: ; ld a, ERROR_CODE ; ld (ERR_NR), a - - + + ERROR_Ok EQU -1 ERROR_SubscriptWrong EQU 2 ERROR_OutOfMemory EQU 3 @@ -144,12 +144,12 @@ __CALL_BACK__: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 - ERROR_InvalidFileName EQU 14 + ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 ERROR_TapeLoadingErr EQU 26 - - + + ; Raises error using RST #8 __ERROR: ld (__ERROR_CODE), a @@ -157,7 +157,7 @@ __ERROR: __ERROR_CODE: nop ret - + ; Sets the error system variable, but keeps running. ; Usually this instruction if followed by the END intermediate instruction. __STOP: @@ -165,10 +165,10 @@ __STOP: ret #line 69 "alloc.asm" #line 1 "heapinit.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -176,25 +176,25 @@ __STOP: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -203,39 +203,39 @@ __STOP: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - - + + + + ; --------------------------------------------------------------------- ; __MEM_INIT must be called to initalize this library with the ; standard parameters @@ -243,57 +243,57 @@ __STOP: __MEM_INIT: ; Initializes the library using (RAMTOP) as start, and ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start ld de, ZXBASIC_HEAP_SIZE ; Change this with your size - + ; --------------------------------------------------------------------- - ; __MEM_INIT2 initalizes this library + ; __MEM_INIT2 initalizes this library ; Parameters: ; HL : Memory address of 1st byte of the memory heap ; DE : Length in bytes of the Memory Heap ; --------------------------------------------------------------------- -__MEM_INIT2: - ; HL as TOP +__MEM_INIT2: + ; HL as TOP PROC - + dec de dec de dec de dec de ; DE = length - 4; HL = start ; This is done, because we require 4 bytes for the empty dummy-header block - + xor a ld (hl), a inc hl ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 inc hl - + ld b, h ld c, l inc bc inc bc ; BC = starts of next block - + ld (hl), c inc hl ld (hl), b inc hl ; Pointer to next block - + ld (hl), e inc hl ld (hl), d inc hl ; Block size (should be length - 4 at start); This block contains all the available memory - + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) inc hl ld (hl), a - + ld a, 201 ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again ret - + ENDP - + #line 70 "alloc.asm" - - + + ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -305,27 +305,27 @@ __MEM_INIT2: ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) ; if the block could not be allocated (out of memory) ; --------------------------------------------------------------------- - + MEM_ALLOC: __MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) PROC - + LOCAL __MEM_LOOP LOCAL __MEM_DONE LOCAL __MEM_SUBTRACT LOCAL __MEM_START LOCAL TEMP, TEMP0 - + TEMP EQU TEMP0 + 1 - + ld hl, 0 ld (TEMP), hl - + __MEM_START: ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start inc bc inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer - + __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l @@ -337,7 +337,7 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE inc hl ld d, (hl) inc hl ; DE = Block Length - + push hl ; HL = *pointer to -> next block ex de, hl or a ; CF = 0 @@ -345,15 +345,15 @@ __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE jp nc, __MEM_DONE pop hl ld (TEMP), hl - + ex de, hl ld e, (hl) inc hl ld d, (hl) ex de, hl jp __MEM_LOOP - -__MEM_DONE: ; A free block has been found. + +__MEM_DONE: ; A free block has been found. ; Check if at least 4 bytes remains free (HL >= 4) push hl exx ; exx to preserve bc @@ -378,14 +378,14 @@ __MEM_DONE: ; A free block has been found. ex de, hl ; HL = Previous block pointer; DE = Next block pointer TEMP0: ld hl, 0 ; Pre-previous block pointer - + ld (hl), e inc hl ld (hl), d ; LINKED pop hl ; Returning block. - + ret - + __MEM_SUBTRACT: ; At this point we have to store HL value (Length - BC) into (DE - 2) ex de, hl @@ -393,50 +393,50 @@ __MEM_SUBTRACT: ld (hl), d dec hl ld (hl), e ; Store new block length - + add hl, de ; New length + DE => free-block start pop de ; Remove previous HL off the stack - + ld (hl), c ; Store length on its 1st word inc hl ld (hl), b inc hl ; Return hl ret - + ENDP - - + + #line 7 "inkey.asm" - + INKEY: - PROC + PROC LOCAL __EMPTY_INKEY LOCAL KEY_SCAN LOCAL KEY_TEST LOCAL KEY_CODE - - ld bc, 3 ; 1 char length string + + ld bc, 3 ; 1 char length string call __MEM_ALLOC - + ld a, h or l ret z ; Return if NULL (No memory) - + push hl ; Saves memory pointer - + call KEY_SCAN jp nz, __EMPTY_INKEY - + call KEY_TEST jp nc, __EMPTY_INKEY - + dec d ; D is expected to be FLAGS so set bit 3 $FF ; 'L' Mode so no keywords. ld e, a ; main key to A ; C is MODE 0 'KLC' from above still. call KEY_CODE ; routine K-DECODE pop hl - + ld (hl), 1 inc hl ld (hl), 0 @@ -445,7 +445,7 @@ INKEY: dec hl dec hl ; HL Points to string result ret - + __EMPTY_INKEY: pop hl xor a @@ -454,16 +454,16 @@ __EMPTY_INKEY: ld (hl), a dec hl ret - + KEY_SCAN EQU 028Eh KEY_TEST EQU 031Eh KEY_CODE EQU 0333h - + ENDP - + #line 35 "valcrash2.bas" #line 1 "storef.asm" - + __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) push de ex de, hl ; DE <- HL @@ -471,7 +471,7 @@ __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory pop hl ; HL <- IX add hl, de ; HL <- IX + HL pop de - + __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register ex af, af' ld a, (hl) @@ -479,7 +479,7 @@ __ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address ld h, (hl) ld l, a ; HL = (HL) ex af, af' - + __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), a inc hl @@ -491,105 +491,105 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL inc hl ld (hl), b ret - + #line 36 "valcrash2.bas" #line 1 "strcat.asm" - - + + #line 1 "strlen.asm" - + ; Returns len if a string ; If a string is NULL, its len is also 0 ; Result returned in HL - + __STRLEN: ; Direct FASTCALL entry ld a, h or l ret z - + ld a, (hl) inc hl ld h, (hl) ; LEN(str) in HL ld l, a ret - - + + #line 3 "strcat.asm" - + __ADDSTR: ; Implements c$ = a$ + b$ ; hl = &a$, de = &b$ (pointers) - - + + __STRCAT2: ; This routine creates a new string in dynamic space ; making room for it. Then copies a$ + b$ into it. ; HL = a$, DE = b$ - + PROC - + LOCAL __STR_CONT LOCAL __STRCATEND - + push hl call __STRLEN ld c, l ld b, h ; BC = LEN(a$) ex (sp), hl ; (SP) = LEN (a$), HL = a$ push hl ; Saves pointer to a$ - + inc bc inc bc ; +2 bytes to store length - + ex de, hl push hl call __STRLEN ; HL = len(b$) - + add hl, bc ; Total str length => 2 + len(a$) + len(b$) - + ld c, l ld b, h ; BC = Total str length + 2 - call __MEM_ALLOC - pop de ; HL = c$, DE = b$ - + call __MEM_ALLOC + pop de ; HL = c$, DE = b$ + ex de, hl ; HL = b$, DE = c$ - ex (sp), hl ; HL = a$, (SP) = b$ - + ex (sp), hl ; HL = a$, (SP) = b$ + exx - pop de ; D'E' = b$ + pop de ; D'E' = b$ exx - + pop bc ; LEN(a$) - + ld a, d or e ret z ; If no memory: RETURN - + __STR_CONT: push de ; Address of c$ - + ld a, h or l jr nz, __STR_CONT1 ; If len(a$) != 0 do copy - + ; a$ is NULL => uses HL = DE for transfer ld h, d ld l, e ld (hl), a ; This will copy 00 00 at (DE) location - inc de ; + inc de ; dec bc ; Ensure BC will be set to 1 in the next step - + __STR_CONT1: ; Copies a$ (HL) into c$ (DE) - inc bc + inc bc inc bc ; BC = BC + 2 ldir ; MEMCOPY: c$ = a$ pop hl ; HL = c$ - + exx push de ; Recovers b$; A ex hl,hl' would be very handy exx - - pop de ; DE = b$ - + + pop de ; DE = b$ + __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ; NOTE: Both DE, BC and AF are modified and lost ; Returns HL (pointer to a$) @@ -597,56 +597,56 @@ __STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ ld a, d or e ret z ; Returns if de is NULL (nothing to copy) - + push hl ; Saves HL to return it later - + ld c, (hl) inc hl ld b, (hl) inc hl add hl, bc ; HL = end of (a$) string ; bc = len(a$) push bc ; Saves LEN(a$) for later - + ex de, hl ; DE = end of string (Begin of copy addr) ld c, (hl) inc hl ld b, (hl) ; BC = len(b$) - + ld a, b or c jr z, __STRCATEND; Return if len(b$) == 0 - + push bc ; Save LEN(b$) inc hl ; Skip 2nd byte of len(b$) ldir ; Concatenate b$ - + pop bc ; Recovers length (b$) pop hl ; Recovers length (a$) add hl, bc ; HL = LEN(a$) + LEN(b$) = LEN(a$+b$) ex de, hl ; DE = LEN(a$+b$) pop hl - + ld (hl), e ; Updates new LEN and return inc hl ld (hl), d dec hl ret - + __STRCATEND: pop hl ; Removes Len(a$) pop hl ; Restores original HL, so HL = a$ ret - + ENDP - + #line 37 "valcrash2.bas" #line 1 "val.asm" - + #line 1 "free.asm" - + ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa - ; (a.k.a. Boriel) + ; (a.k.a. Boriel) ; http://www.boriel.com ; ; This ASM library is licensed under the BSD license @@ -654,25 +654,25 @@ __STRCATEND: ; closed source programs). ; ; Please read the BSD license on the internet - + ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. - + ; Each free block contains this info: - ; - ; +----------------+ <-- HEAP START + ; + ; +----------------+ <-- HEAP START ; | Size (2 bytes) | ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK ; +----------------+ ; | Next (2 bytes) |---+ - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | <-- If Size > 4, then this contains (size - 4) bytes ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ @@ -681,38 +681,38 @@ __STRCATEND: ; | (0 if Size = 4)| | ; +----------------+ | ; | <-- This zone is in use (Already allocated) - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Size (2 bytes) | ; +----------------+ ; | Next (2 bytes) |---+ ; +----------------+ | ; | | | ; | (0 if Size = 4)| | - ; +----------------+ <-+ + ; +----------------+ <-+ ; | Next (2 bytes) |--> NULL => END OF LIST ; | 0 = NULL | ; +----------------+ ; | | ; | (0 if Size = 4)| ; +----------------+ - - + + ; When a block is FREED, the previous and next pointers are examined to see ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). - - + + ; MEMORY MANAGER ; - ; This library must be initialized calling __MEM_INIT with + ; This library must be initialized calling __MEM_INIT with ; HL = BLOCK Start & DE = Length. - + ; An init directive is useful for initialization routines. ; They will be added automatically if needed. - - - + + + ; --------------------------------------------------------------------- ; MEM_FREE ; Frees a block of memory @@ -721,57 +721,57 @@ __STRCATEND: ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing ; is done ; --------------------------------------------------------------------- - + MEM_FREE: __MEM_FREE: ; Frees the block pointed by HL ; HL DE BC & AF modified PROC - + LOCAL __MEM_LOOP2 LOCAL __MEM_LINK_PREV LOCAL __MEM_JOIN_TEST LOCAL __MEM_BLOCK_JOIN - + ld a, h or l ret z ; Return if NULL pointer - + dec hl dec hl ld b, h ld c, l ; BC = Block pointer - + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start - + __MEM_LOOP2: inc hl inc hl ; Next block ptr - + ld e, (hl) inc hl ld d, (hl) ; Block next ptr ex de, hl ; DE = &(block->next); HL = block->next - + ld a, h ; HL == NULL? or l jp z, __MEM_LINK_PREV; if so, link with previous - + or a ; Clear carry flag sbc hl, bc ; Carry if BC > HL => This block if before add hl, bc ; Restores HL, preserving Carry flag jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block - + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next - + __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL ex de, hl push hl dec hl - + ld (hl), c inc hl ld (hl), b ; (DE) <- BC - + ld h, b ; HL <- BC (Free block ptr) ld l, c inc hl ; Skip block length (2 bytes) @@ -780,47 +780,47 @@ __MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL inc hl ld (hl), d ; --- LINKED ; HL = &(BC->next) + 2 - + call __MEM_JOIN_TEST pop hl - + __MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them ; hl = Ptr to current block + 2 ld d, (hl) dec hl ld e, (hl) - dec hl + dec hl ld b, (hl) ; Loads block length into BC dec hl ld c, (hl) ; - + push hl ; Saves it for later add hl, bc ; Adds its length. If HL == DE now, it must be joined or a sbc hl, de ; If Z, then HL == DE => We must join pop hl ret nz - + __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC push hl ; Saves it for later ex de, hl - + ld e, (hl) ; DE -> block->next->length inc hl ld d, (hl) inc hl - + ex de, hl ; DE = &(block->next) add hl, bc ; HL = Total Length - + ld b, h ld c, l ; BC = Total Length - + ex de, hl ld e, (hl) inc hl ld d, (hl) ; DE = block->next - + pop hl ; Recovers Pointer to block ld (hl), c inc hl @@ -830,43 +830,43 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed inc hl ld (hl), d ; Next saved ret - + ENDP - + #line 2 "val.asm" #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -882,15 +882,15 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 3 "val.asm" - - + + VAL: ; Computes VAL(a$) using ROM FP-CALC ; HL = address of a$ ; Returns FP number in C ED LH registers ; A Register = 1 => Free a$ on return - + PROC - + LOCAL STK_STO_S LOCAL __RET_ZERO LOCAL ERR_SP @@ -900,107 +900,107 @@ VAL: ; Computes VAL(a$) using ROM FP-CALC LOCAL __VAL_ERROR LOCAL __VAL_EMPTY LOCAL SET_MIN - + RECLAIM1 EQU 6629 STKBOT EQU 23651 ERR_SP EQU 23613 CH_ADD EQU 23645 STK_STO_S EQU 2AB2h SET_MIN EQU 16B0h - + ld d, a ; Preserves A register in DE ld a, h or l - jr z, __RET_ZERO ; NULL STRING => Return 0 - + jr z, __RET_ZERO ; NULL STRING => Return 0 + push de ; Saves A Register (now in D) push hl ; Not null string. Save its address for later - + ld c, (hl) inc hl ld b, (hl) inc hl - + ld a, b or c jr z, __VAL_EMPTY ; Jumps VAL_EMPTY on empty string - + ex de, hl ; DE = String start - + ld hl, (CH_ADD) push hl - + ld hl, (STKBOT) push hl - + ld hl, (ERR_SP) push hl - + ;; Now put our error handler on ERR_SP ld hl, __VAL_ERROR push hl ld hl, 0 add hl, sp ld (ERR_SP), hl - + call STK_STO_S ; Enter it on the stack - + ld b, 1Dh ; "VAL" rst 28h ; ROM CALC defb 1Dh ; VAL defb 38h ; END CALC - + pop hl ; Discards our current error handler pop hl ld (ERR_SP), hl ; Restores ERR_SP - + pop de ; old STKBOT ld hl, (STKBOT) ; current SKTBOT call RECLAIM1 ; Recover unused space - + pop hl ; Discards old CH_ADD value pop hl ; String pointer pop af ; Deletion flag or a call nz, __MEM_FREE ; Frees string content before returning - + ld a, ERROR_Ok ; Sets OK in the result ld (ERR_NR), a - + jp __FPSTACK_POP ; Recovers result and return from there - + __VAL_ERROR: ; Jumps here on ERROR pop hl ld (ERR_SP), hl ; Restores ERR_SP - + ld hl, (STKBOT) ; current SKTBOT pop de ; old STKBOT pop hl ld (CH_ADD), hl ; Recovers old CH_ADD - + call 16B0h ; Resets temporary areas after an error - + __VAL_EMPTY: ; Jumps here on empty string pop hl ; Recovers initial string address pop af ; String flag: If not 0 => it's temporary or a call nz, __MEM_FREE ; Frees "" string - + __RET_ZERO: ; Returns 0 Floating point on error ld a, ERROR_Ok ld (ERR_NR), a - + xor a ld b, a ld c, a ld d, b ld e, c ret - + ENDP - + #line 38 "valcrash2.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00, 00 diff --git a/tests/functional/while.asm b/tests/functional/while.asm index 2822e06bf..9f9f47e66 100644 --- a/tests/functional/while.asm +++ b/tests/functional/while.asm @@ -55,41 +55,41 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "ltf.asm" - + #line 1 "u32tofreg.asm" - + #line 1 "neg32.asm" - + __ABS32: bit 7, d ret z - + __NEG32: ; Negates DEHL (Two's complement) ld a, l cpl ld l, a - + ld a, h cpl ld h, a - + ld a, e cpl ld e, a - + ld a, d cpl ld d, a - + inc l ret nz - + inc h ret nz - + inc de ret - + #line 2 "u32tofreg.asm" __I8TOFREG: ld l, a @@ -98,35 +98,35 @@ __I8TOFREG: ld h, a ld e, a ld d, a - + __I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) ; to a Floating Point Number returned in (A ED CB) - + ld a, d or a ; Test sign - + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned - + call __NEG32 ; Convert it to positive call __U32TOFREG ; Convert it to Floating point - + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa ret - + __U8TOFREG: ; Converts an unsigned 8 bit (A) to Floating point ld l, a ld h, 0 ld e, h ld d, h - + __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ; to a Floating point number returned in A ED CB - + PROC - + LOCAL __U32TOFREG_END - + ld a, d or e or h @@ -134,20 +134,20 @@ __U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) ld b, d ld c, e ; Returns 00 0000 0000 if ZERO ret z - + push de push hl - + exx - pop de ; Loads integer into B'C' D'E' + pop de ; Loads integer into B'C' D'E' pop bc exx - + ld l, 128 ; Exponent ld bc, 0 ; DEBC = 0 ld d, b ld e, c - + __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG exx ld a, d ; B'C'D'E' == 0 ? @@ -155,46 +155,46 @@ __U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG or b or c jp z, __U32TOFREG_END ; We are done - + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry rr c rr d rr e exx - + rr e ; Shift EDCB >> 1, inserting the carry on the left rr d rr c rr b - + inc l ; Increment exponent jp __U32TOFREG_LOOP - - + + __U32TOFREG_END: exx ld a, l ; Puts the exponent in a res 7, e ; Sets the sign bit to 0 (positive) - + ret ENDP - + #line 2 "ltf.asm" #line 1 "ftou32reg.asm" - - - + + + __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) ; Input FP number in A EDCB (A exponent, EDCB mantissa) ; Output: DEHL 32 bit number (signed) PROC - + LOCAL __IS_FLOAT - + or a - jr nz, __IS_FLOAT + jr nz, __IS_FLOAT ; Here if it is a ZX ROM Integer - + ld h, c ld l, d ld a, e ; Takes sign: FF = -, 0 = + @@ -202,96 +202,96 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS inc a jp z, __NEG32 ; Negates if negative ret - + __IS_FLOAT: ; Jumps here if it is a true floating point number - ld h, e + ld h, e push hl ; Stores it for later (Contains Sign in H) - + push de push bc - + exx - pop de ; Loads mantissa into C'B' E'D' - pop bc ; - + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + set 7, c ; Highest mantissa bit is always 1 exx - + ld hl, 0 ; DEHL = 0 ld d, h ld e, l - + ;ld a, c ; Get exponent sub 128 ; Exponent -= 128 jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) - + ld b, a ; Loop counter = exponent - 128 - + __FTOU32REG_LOOP: exx ; Shift C'B' E'D' << 1, output bit stays in Carry sla d rl e rl b rl c - + exx ; Shift DEHL << 1, inserting the carry on the right rl l rl h rl e rl d - + djnz __FTOU32REG_LOOP - + __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative jp m, __NEG32 ; Negates DEHL - + ret - + ENDP - - + + __FTOU8: ; Converts float in C ED LH to Unsigned byte in A call __FTOU32REG ld a, l ret - + #line 3 "ltf.asm" #line 1 "stackf.asm" - + ; ------------------------------------------------------------- ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC ; ------------------------------------------------------------- - - + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) - + __FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) ; Second argument to push into the stack calculator is popped out of the stack ; Since the caller routine also receives the parameters into the top of the stack ; four bytes must be removed from SP before pop them out - + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK exx pop hl ; Caller-Caller return addr exx pop hl ; Caller return addr - + pop af pop de pop bc - + push hl ; Caller return addr exx push hl ; Caller-Caller return addr exx - + jp __FPSTACK_PUSH - - + + __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ; This format is specified in the ZX 48K Manual ; You can push a 16 bit signed integer as @@ -307,38 +307,38 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ld b, a jp __FPSTACK_PUSH #line 4 "ltf.asm" - + ; ------------------------------------------------------------- ; Floating point library using the FP ROM Calculator (ZX 48K) - + ; All of them uses A EDCB registers as 1st paramter. ; For binary operators, the 2n operator must be pushed into the ; stack, in the order A HL BC. ; ; Uses CALLEE convention ; ------------------------------------------------------------- - + __LTF: ; A < B call __FPSTACK_PUSH2 ; Enters B, A - + ; ------------- ROM NOS-LESS ld b, 0Ch ; A > B (Operands stack-reversed) rst 28h defb 0Ch; ; A > B defb 38h; ; END CALC - - call __FPSTACK_POP + + call __FPSTACK_POP jp __FTOU8 ; Convert to 8 bits - + #line 46 "while.bas" #line 1 "pushf.asm" - - - ; Routine to push Float pointed by HL + + + ; Routine to push Float pointed by HL ; Into the stack. Notice that the hl points to the last ; byte of the FP number. ; Uses H'L' B'C' and D'E' to preserve ABCDEHL registers - + __FP_PUSH_REV: push hl exx @@ -359,10 +359,10 @@ __FP_PUSH_REV: push bc ; Return Address exx ret - - + + #line 47 "while.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00, 00 diff --git a/tests/functional/xor16.asm b/tests/functional/xor16.asm index 170d40922..6e1ac25fb 100644 --- a/tests/functional/xor16.asm +++ b/tests/functional/xor16.asm @@ -51,39 +51,39 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "xor16.asm" - - + + ; XOR16 implemented in XOR8.ASM file #line 1 "xor8.asm" - + ; vim:ts=4:et: ; FASTCALL boolean xor 8 version. ; result in Accumulator (0 False, not 0 True) ; __FASTCALL__ version (operands: A, H) ; Performs 8bit xor 8bit and returns the boolean - + __XOR16: ld a, h or l ld h, a - + ld a, d or e - + __XOR8: sub 1 sbc a, a ld l, a ; l = 00h or FFh - + ld a, h sub 1 sbc a, a ; a = 00h or FFh xor l - ret - + ret + #line 4 "xor16.asm" #line 42 "xor16.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00 diff --git a/tests/functional/xor32.asm b/tests/functional/xor32.asm index a8c81a5eb..b82863de9 100644 --- a/tests/functional/xor32.asm +++ b/tests/functional/xor32.asm @@ -67,48 +67,48 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "xor32.asm" - + ; FASTCALL boolean xor 8 version. ; result in Accumulator (0 False, not 0 True) ; __FASTCALL__ version (operands: A, H) ; Performs 32bit xor 32bit and returns the boolean - + #line 1 "xor8.asm" - + ; vim:ts=4:et: ; FASTCALL boolean xor 8 version. ; result in Accumulator (0 False, not 0 True) ; __FASTCALL__ version (operands: A, H) ; Performs 8bit xor 8bit and returns the boolean - + __XOR16: ld a, h or l ld h, a - + ld a, d or e - + __XOR8: sub 1 sbc a, a ld l, a ; l = 00h or FFh - + ld a, h sub 1 sbc a, a ; a = 00h or FFh xor l - ret - + ret + #line 7 "xor32.asm" - + __XOR32: ld a, h or l or d or e ld c, a - + pop hl ; RET address pop de ex (sp), hl @@ -118,9 +118,9 @@ __XOR32: or e ld h, c jp __XOR8 - + #line 58 "xor32.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00, 00, 00, 00 diff --git a/tests/functional/xor8.asm b/tests/functional/xor8.asm index 080f3a266..9b4518f13 100644 --- a/tests/functional/xor8.asm +++ b/tests/functional/xor8.asm @@ -43,34 +43,34 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 #line 1 "xor8.asm" - + ; vim:ts=4:et: ; FASTCALL boolean xor 8 version. ; result in Accumulator (0 False, not 0 True) ; __FASTCALL__ version (operands: A, H) ; Performs 8bit xor 8bit and returns the boolean - + __XOR16: ld a, h or l ld h, a - + ld a, d or e - + __XOR8: sub 1 sbc a, a ld l, a ; l = 00h or FFh - + ld a, h sub 1 sbc a, a ; a = 00h or FFh xor l - ret - + ret + #line 34 "xor8.bas" - + ZXBASIC_USER_DATA: _a: DEFB 00 diff --git a/zxb.py b/zxb.py index b7408b507..61bbb2de1 100755 --- a/zxb.py +++ b/zxb.py @@ -50,7 +50,8 @@ def output(memory, ofile=None): and writes it to the given file or to the screen if no file is passed """ for m in memory: - if len(m) > 0 and m[0] == '#': # Preprocessor directive? + m = m.rstrip('\r\n\t ') # Ensures no trailing newlines (might with upon includes) + if m and m[0] == '#': # Preprocessor directive? if ofile is None: print(m) else: @@ -58,7 +59,7 @@ def output(memory, ofile=None): continue # Prints a 4 spaces "tab" for non labels - if ':' not in m: + if m and ':' not in m: if ofile is None: print(' '), else: From 820fca944238a1af51054a3d36a14182738795ae Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 6 Oct 2017 23:39:03 +0200 Subject: [PATCH 074/247] add test for READ errors --- tests/functional/test_.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/functional/test_.py b/tests/functional/test_.py index c7f8f286f..a4d6e3917 100755 --- a/tests/functional/test_.py +++ b/tests/functional/test_.py @@ -94,6 +94,14 @@ strict.bas:4: strict mode: missing type declaration for 'a' >>> process_file('errletfunc.bas') errletfunc.bas:5: Cannot assign a value to 'x'. It's not a variable +>>> process_file('read0.bas') +read0.bas:12: 'x' is SUBROUTINE not a FUNCTION +>>> process_file('read1.bas') +read1.bas:11: Variable 'x' is an array and cannot be used in this context +>>> process_file('read3.bas') +read3.bas:9: 'x' is neither an array nor a function. +>>> process_file('read6.bas') +read6.bas:12: Syntax error. Can only read a variable or an array element """ From aecf024863d4a49b2bcd03405526c1e3eebc964c Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 6 Oct 2017 23:58:36 +0200 Subject: [PATCH 075/247] update Changelog --- ChangeLog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ChangeLog b/ChangeLog index 81aa39309..f5df99884 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +================================================================ +Changes from Version 1.6.13 to 1.7.0 ++ Added READ, DATA, RESTORE (finally!) ++ Allows to call SUBs with no parenthesis (e.g. mySUB 1, 2+a) ++ Allows to call FUNCTIONS with 1 or no params with no parenthesis ++ Some bug fixes for better stability + ================================================================ Changes from Version 1.6.12 to 1.6.13 ! Fixes and improves strict mode checking From ef12716d2ad312300964a10534b6040082ec3aef Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 6 Oct 2017 23:58:53 +0200 Subject: [PATCH 076/247] =?UTF-8?q?Bump=20version:=201.6.12=20=E2=86=92=20?= =?UTF-8?q?1.7.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 7724e9c6c..f67999c50 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,4 +1,4 @@ [bumpversion] -current_version = 1.6.12 +current_version = 1.7.0 files = version.py diff --git a/version.py b/version.py index e90219384..81af48306 100755 --- a/version.py +++ b/version.py @@ -1 +1 @@ -VERSION = '1.6.12' +VERSION = '1.7.0' From 543acdc587134b4067cdca359386db46447f929d Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 10 Oct 2017 15:30:36 +0200 Subject: [PATCH 077/247] bugfix: fix a crash upon some wrong DATA lines If a DATA expression referenced an undeclared array element, the compiler might crash. Fixed. --- tests/functional/data0.bas | 3 +++ tests/functional/test_.py | 2 ++ zxbparser.py | 5 +++++ 3 files changed, 10 insertions(+) create mode 100644 tests/functional/data0.bas diff --git a/tests/functional/data0.bas b/tests/functional/data0.bas new file mode 100644 index 000000000..b6286f25b --- /dev/null +++ b/tests/functional/data0.bas @@ -0,0 +1,3 @@ +DIM a as Byte +DATA a, b(2) + diff --git a/tests/functional/test_.py b/tests/functional/test_.py index a4d6e3917..d28595a8c 100755 --- a/tests/functional/test_.py +++ b/tests/functional/test_.py @@ -102,6 +102,8 @@ read3.bas:9: 'x' is neither an array nor a function. >>> process_file('read6.bas') read6.bas:12: Syntax error. Can only read a variable or an array element +>>> process_file('data0.bas') +data0.bas:2: 'b' is neither an array nor a function. """ diff --git a/zxbparser.py b/zxbparser.py index 11970ac17..d6b65882d 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -1552,6 +1552,11 @@ def p_data(p): label_ = make_label(gl.DATA_PTR_CURRENT, lineno=p.lineno(1)) datas_ = [] funcs = [] + + if p[2] is None: + p[0] = None + return + for d in p[2].children: value = d.value if is_static(value): From a5286ff86d76b631aaf004f970d64b67a5bbdb23 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Thu, 12 Oct 2017 23:20:38 +0200 Subject: [PATCH 078/247] move flatten_list() function to api This refacts and moves out a very generic function. Also uses list method which are faster. --- api/utils.py | 14 +++++++++++++- arch/zx48k/optimizer.py | 13 +------------ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/api/utils.py b/api/utils.py index 1852f41be..7ee07b784 100644 --- a/api/utils.py +++ b/api/utils.py @@ -6,7 +6,7 @@ from . import errmsg -__all__ = ['read_txt_file', 'open_file', 'sanitize_filename'] +__all__ = ['read_txt_file', 'open_file', 'sanitize_filename', 'flatten_list'] __doc__ = """Utils module contains many helpers for several task, like reading files or path management""" @@ -60,3 +60,15 @@ def current_data_label(): a new DATA line is declared """ return '__DATA__{0}'.format(len(global_.DATAS)) + + +def flatten_list(x): + result = [] + + for l in x: + if not isinstance(l, list): + result.append(l) + else: + result.extend(flatten_list(l)) + + return result diff --git a/arch/zx48k/optimizer.py b/arch/zx48k/optimizer.py index f82e9506a..07c2cecc1 100644 --- a/arch/zx48k/optimizer.py +++ b/arch/zx48k/optimizer.py @@ -12,6 +12,7 @@ from api.errors import Error from api.config import OPTIONS from api.debug import __DEBUG__ +from api.utils import flatten_list from identityset import IdentitySet import asmlex import arch.zx48k.backend @@ -2130,18 +2131,6 @@ def partition_block(block): return result -def flatten_list(x): - result = [] - - for l in x: - if not isinstance(l, list): - result += [l] - else: - result += flatten_list(l) - - return result - - # --------------------------------------------------------------------------------------- def get_basic_blocks(bb): From 06afc81fc6bf3cefb3330809e785688ed8759755 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Thu, 12 Oct 2017 23:23:50 +0200 Subject: [PATCH 079/247] bugfix: prevents DATA functs to be optimized The peephole optimizer (-O3) cannot detect register dependencies in DATA so use #pragmas to tell the optimizer about them This new pragma is #pragma opt required reg, reg, reg... and tells the optimizer those registers (8, 16 bits) are required. --- arch/zx48k/backend/__init__.py | 6 + arch/zx48k/optimizer.py | 15 +- tests/functional/opt3_data2.asm | 2929 +++++++++++++++++++++++++++++++ tests/functional/opt3_data2.bas | 11 + 4 files changed, 2959 insertions(+), 2 deletions(-) create mode 100644 tests/functional/opt3_data2.asm create mode 100644 tests/functional/opt3_data2.bas diff --git a/arch/zx48k/backend/__init__.py b/arch/zx48k/backend/__init__.py index e0e69a286..8dba89589 100644 --- a/arch/zx48k/backend/__init__.py +++ b/arch/zx48k/backend/__init__.py @@ -1376,6 +1376,7 @@ def _ret8(ins): """ Returns from a procedure / function an 8bits value """ output = _8bit_oper(ins.quad[1]) + output.append('#pragma opt require a') output.append('jp %s' % str(ins.quad[2])) return output @@ -1384,6 +1385,7 @@ def _ret16(ins): """ Returns from a procedure / function a 16bits value """ output = _16bit_oper(ins.quad[1]) + output.append('#pragma opt require hl') output.append('jp %s' % str(ins.quad[2])) return output @@ -1392,6 +1394,7 @@ def _ret32(ins): """ Returns from a procedure / function a 32bits value (even Fixed point) """ output = _32bit_oper(ins.quad[1]) + output.append('#pragma opt require hl,de') output.append('jp %s' % str(ins.quad[2])) return output @@ -1400,6 +1403,7 @@ def _retf16(ins): """ Returns from a procedure / function a Fixed Point (32bits) value """ output = _f16_oper(ins.quad[1]) + output.append('#pragma opt require hl,de') output.append('jp %s' % str(ins.quad[2])) return output @@ -1408,6 +1412,7 @@ def _retf(ins): """ Returns from a procedure / function a Floating Point (40bits) value """ output = _float_oper(ins.quad[1]) + output.append('#pragma opt require a,bc,de') output.append('jp %s' % str(ins.quad[2])) return output @@ -1421,6 +1426,7 @@ def _retstr(ins): output.append('call __LOADSTR') REQUIRES.add('loadstr.asm') + output.append('#pragma opt require hl') output.append('jp %s' % str(ins.quad[2])) return output diff --git a/arch/zx48k/optimizer.py b/arch/zx48k/optimizer.py index 07c2cecc1..51b2f481f 100644 --- a/arch/zx48k/optimizer.py +++ b/arch/zx48k/optimizer.py @@ -50,6 +50,7 @@ RE_INDIR16 = re.compile('r[ \t]*\([ \t]*([dD][eE])|([hH][lL])[ \t]*\)[ \t]*') RE_OUTC = re.compile('[ \t]*\([ \t]*[cC]\)') RE_ID = re.compile('[.a-zA-Z_][.a-zA-Z_0-9]*') +RE_PRAGMA = re.compile('^#[ \t]?pragma[ \t]opt[ \t]') # Enabled Optimizations (this is useful for debugging) OPT00 = True @@ -1054,6 +1055,15 @@ def requires(self): if self.asm in arch.zx48k.backend.ASMS: return ALL_REGS + if self.inst == '#pragma': + tmp = self.__instr.split(' ')[1:] + if tmp[0] != 'opt': + return + if tmp[1] == 'require': + return set(flatten_list([single_registers(x.strip(', \t\r')) for x in tmp[2:]])) + + return set([]) + result = set([]) i = self.inst o = [x.lower() for x in self.opers] @@ -2332,7 +2342,7 @@ def optimize(initial_memory): cleanupmem(initial_memory) if OPTIONS.optimization.value <= 2: - return '\n'.join(initial_memory) + return '\n'.join(x for x in initial_memory if not RE_PRAGMA.match(x)) optimize_init() bb = BasicBlock(initial_memory) @@ -2361,4 +2371,5 @@ def optimize(initial_memory): if x.comes_from == [] and len([y for y in JUMP_LABELS if x is LABELS[y].basic_block]): x.ignored = True - return '\n'.join(flatten_list([x.asm for x in basic_blocks if not x.ignored])) + return '\n'.join([y for y in flatten_list([x.asm for x in basic_blocks if not x.ignored]) + if not RE_PRAGMA.match(y)]) diff --git a/tests/functional/opt3_data2.asm b/tests/functional/opt3_data2.asm new file mode 100644 index 000000000..8b49f43f7 --- /dev/null +++ b/tests/functional/opt3_data2.asm @@ -0,0 +1,2929 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + call __PRINT_INIT + xor a + ld (_i), a + jp __LABEL0 +__LABEL3: + ld a, 3 + call __READ + push af + ld a, (_i) + ld l, a + ld h, 0 + push hl + ld hl, _a + call __ARRAY + pop af + ld (hl), a + ld a, (_i) + ld l, a + ld h, 0 + push hl + ld hl, _a + call __ARRAY + ld a, (hl) + call __PRINTU8 + call PRINT_EOL + ld hl, _i + inc (hl) +__LABEL0: + ld a, 9 + ld hl, (_i - 1) + cp h + jp nc, __LABEL3 + ld bc, 0 +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + pop iy + pop ix + exx + ei + ret +__CALL_BACK__: + DEFW 0 +___DATA__FUNCPTR__0: + ld a, (_i) + ld h, 6 + call __MUL8_FAST +___DATA__FUNCPTR__0__leave: + ret +___DATA__FUNCPTR__1: + ld a, (_a + 3) +___DATA__FUNCPTR__1__leave: + ret +___DATA__FUNCPTR__2: + ld a, (_a + 4) +___DATA__FUNCPTR__2__leave: + ret +___DATA__FUNCPTR__3: + ld a, (_a + 5) +___DATA__FUNCPTR__3__leave: + ret +___DATA__FUNCPTR__4: + ld a, (_a + 6) +___DATA__FUNCPTR__4__leave: + ret +___DATA__FUNCPTR__5: + ld a, (_a + 7) +___DATA__FUNCPTR__5__leave: + ret +__DATA__0: + DEFB 3 + DEFB 2 + DEFB 3 + DEFB 4 + DEFB 83h + DEFW ___DATA__FUNCPTR__0 + DEFB 3 + DEFB 7 + DEFB 3 + DEFB 0 +__DATA__1: + DEFB 83h + DEFW ___DATA__FUNCPTR__1 + DEFB 83h + DEFW ___DATA__FUNCPTR__2 + DEFB 83h + DEFW ___DATA__FUNCPTR__3 + DEFB 83h + DEFW ___DATA__FUNCPTR__4 + DEFB 83h + DEFW ___DATA__FUNCPTR__5 +__DATA__END: + DEFB 00h +#line 1 "array.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; ------------------------------------------------------------------- + ; Simple array Index routine + ; Number of total indexes dimensions - 1 at beginning of memory + ; HL = Start of array memory (First two bytes contains N-1 dimensions) + ; Dimension values on the stack, (top of the stack, highest dimension) + ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> + + ; For any array of N dimension A(aN-1, ..., a1, a0) + ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as + ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] +; What I will do here is to calculate the following sequence: + ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... + + +#line 1 "mul16.asm" + +__MUL16: ; Mutiplies HL with the last value stored into de stack + ; Works for both signed and unsigned + + PROC + + LOCAL __MUL16LOOP + LOCAL __MUL16NOADD + + ex de, hl + pop hl ; Return address + ex (sp), hl ; CALLEE caller convention + +;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand + ;; ld c, h + ;; ld a, l ; C,A => 1st Operand + ;; + ;; ld hl, 0 ; Accumulator + ;; ld b, 16 + ;; +;;__MUL16LOOP: + ;; sra c ; C,A >> 1 (Arithmetic) + ;; rra + ;; + ;; jr nc, __MUL16NOADD + ;; add hl, de + ;; +;;__MUL16NOADD: + ;; sla e + ;; rl d + ;; + ;; djnz __MUL16LOOP + +__MUL16_FAST: + ld b, 16 + ld a, d + ld c, e + ex de, hl + ld hl, 0 + +__MUL16LOOP: + add hl, hl ; hl << 1 + sla c + rla ; a,c << 1 + jp nc, __MUL16NOADD + add hl, de + +__MUL16NOADD: + djnz __MUL16LOOP + + ret ; Result in hl (16 lower bits) + + ENDP + +#line 20 "array.asm" + +#line 24 "/src/zxb/trunk/library-asm/array.asm" + +__ARRAY: + PROC + + LOCAL LOOP + LOCAL ARRAY_END + LOCAL RET_ADDRESS ; Stores return address + + ex (sp), hl ; Return address in HL, array address in the stack + ld (RET_ADDRESS + 1), hl ; Stores it for later + + exx + pop hl ; Will use H'L' as the pointer + ld c, (hl) ; Loads Number of dimensions from (hl) + inc hl + ld b, (hl) + inc hl ; Ready + exx + + ld hl, 0 ; BC = Offset "accumulator" + +#line 48 "/src/zxb/trunk/library-asm/array.asm" + +LOOP: + pop bc ; Get next index (Ai) from the stack + +#line 60 "/src/zxb/trunk/library-asm/array.asm" + + add hl, bc ; Adds current index + + exx ; Checks if B'C' = 0 + ld a, b ; Which means we must exit (last element is not multiplied by anything) + or c + jr z, ARRAY_END ; if B'Ci == 0 we are done + + ld e, (hl) ; Loads next dimension into D'E' + inc hl + ld d, (hl) + inc hl + push de + dec bc ; Decrements loop counter + exx + pop de ; DE = Max bound Number (i-th dimension) + +#line 80 "/src/zxb/trunk/library-asm/array.asm" + ;call __MUL16_FAST ; HL *= DE + call __FNMUL +#line 86 "/src/zxb/trunk/library-asm/array.asm" + jp LOOP + +ARRAY_END: + ld e, (hl) + inc hl + ld d, c ; C = 0 => DE = E = Element size + push hl + push de + exx + +#line 100 "/src/zxb/trunk/library-asm/array.asm" + LOCAL ARRAY_SIZE_LOOP + + ex de, hl + ld hl, 0 + pop bc + ld b, c +ARRAY_SIZE_LOOP: + add hl, de + djnz ARRAY_SIZE_LOOP + + ;; Even faster + ;pop bc + + ;ld d, h + ;ld e, l + + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, hl + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, hl + ;dec c + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, de + ;__ARRAY_FIN: +#line 131 "/src/zxb/trunk/library-asm/array.asm" + + pop de + add hl, de ; Adds element start + +RET_ADDRESS: + ld de, 0 + push de + ret ; HL = (Start of Elements + Offset) + + ;; Performs a faster multiply for little 16bit numbs + LOCAL __FNMUL, __FNMUL2 + +__FNMUL: + xor a + or d + jp nz, __MUL16_FAST + + or e + ex de, hl + ret z + + cp 33 + jp nc, __MUL16_FAST + + ld b, l + ld l, h ; HL = 0 + +__FNMUL2: + add hl, de + djnz __FNMUL2 + ret + + ENDP + +#line 97 "opt3_data2.bas" +#line 1 "mul8.asm" + +__MUL8: ; Performs 8bit x 8bit multiplication + PROC + + ;LOCAL __MUL8A + LOCAL __MUL8LOOP + LOCAL __MUL8B + ; 1st operand (byte) in A, 2nd operand into the stack (AF) + pop hl ; return address + ex (sp), hl ; CALLE convention + +;;__MUL8_FAST: ; __FASTCALL__ entry + ;; ld e, a + ;; ld d, 0 + ;; ld l, d + ;; + ;; sla h + ;; jr nc, __MUL8A + ;; ld l, e + ;; +;;__MUL8A: + ;; + ;; ld b, 7 +;;__MUL8LOOP: + ;; add hl, hl + ;; jr nc, __MUL8B + ;; + ;; add hl, de + ;; +;;__MUL8B: + ;; djnz __MUL8LOOP + ;; + ;; ld a, l ; result = A and HL (Truncate to lower 8 bits) + +__MUL8_FAST: ; __FASTCALL__ entry, a = a * h (8 bit mul) and Carry + + ld b, 8 + ld l, a + xor a + +__MUL8LOOP: + add a, a ; a *= 2 + sla l + jp nc, __MUL8B + add a, h + +__MUL8B: + djnz __MUL8LOOP + + ret ; result = HL + ENDP + +#line 98 "opt3_data2.bas" +#line 1 "print.asm" + +; vim:ts=4:sw=4:et: + ; PRINT command routine + ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that + +#line 1 "sposn.asm" + + ; Printing positioning library. + PROC + LOCAL ECHO_E + +__LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. + ld de, (S_POSN) + ld hl, (MAXX) + or a + sbc hl, de + ex de, hl + ret + + +__SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. + ld hl, (MAXX) + or a + sbc hl, de + ld (S_POSN), hl ; saves it again + ret + + + ECHO_E EQU 23682 + MAXX EQU ECHO_E ; Max X position + 1 + MAXY EQU MAXX + 1 ; Max Y position + 1 + + S_POSN EQU 23688 + POSX EQU S_POSN ; Current POS X + POSY EQU S_POSN + 1 ; Current POS Y + + ENDP + +#line 6 "print.asm" +#line 1 "cls.asm" + + ; JUMPS directly to spectrum CLS + ; This routine does not clear lower screen + + ;CLS EQU 0DAFh + + ; Our faster implementation + + + +CLS: + PROC + + LOCAL COORDS + LOCAL __CLS_SCR + LOCAL ATTR_P + LOCAL SCREEN + + ld hl, 0 + ld (COORDS), hl + ld hl, 1821h + ld (S_POSN), hl +__CLS_SCR: + ld hl, SCREEN + ld (hl), 0 + ld d, h + ld e, l + inc de + ld bc, 6144 + ldir + + ; Now clear attributes + + ld a, (ATTR_P) + ld (hl), a + ld bc, 767 + ldir + ret + + COORDS EQU 23677 + SCREEN EQU 16384 ; Default start of the screen (can be changed) + ATTR_P EQU 23693 + ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address + + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines + ; to get the start of the screen + ENDP + +#line 7 "print.asm" +#line 1 "in_screen.asm" + + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 3 "in_screen.asm" + +__IN_SCREEN: + ; Returns NO carry if current coords (D, E) + ; are OUT of the screen limits (MAXX, MAXY) + + PROC + LOCAL __IN_SCREEN_ERR + + ld hl, MAXX + ld a, e + cp (hl) + jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + + ld a, d + inc hl + cp (hl) + ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + ;; ret + ret c ; Return if carry (OK) + +__IN_SCREEN_ERR: +__OUT_OF_SCREEN_ERR: + ; Jumps here if out of screen + ld a, ERROR_OutOfScreen + jp __STOP ; Saves error code and exits + + ENDP +#line 8 "print.asm" +#line 1 "table_jump.asm" + + +JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A + add a, a + +JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE + ld e, a + ld d, 0 + +JUMP_HL_PLUS_DE: ; Does JP (HL + DE) + add hl, de + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl +CALL_HL: + jp (hl) + +#line 9 "print.asm" +#line 1 "ink.asm" + + ; Sets ink color in ATTR_P permanently +; Parameter: Paper color in A register + +#line 1 "const.asm" + + ; Global constants + + P_FLAG EQU 23697 + FLAGS2 EQU 23681 + ATTR_P EQU 23693 ; permanet ATTRIBUTES + ATTR_T EQU 23695 ; temporary ATTRIBUTES + CHARS EQU 23606 ; Pointer to ROM/RAM Charset + UDG EQU 23675 ; Pointer to UDG Charset + MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars + +#line 5 "ink.asm" + +INK: + PROC + LOCAL __SET_INK + LOCAL __SET_INK2 + + ld de, ATTR_P + +__SET_INK: + cp 8 + jr nz, __SET_INK2 + + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + or 7 ; Set bits 0,1,2 to enable transparency + ld (de), a + ret + +__SET_INK2: + ; Another entry. This will set the ink color at location pointer by DE + and 7 ; # Gets color mod 8 + ld b, a ; Saves the color + ld a, (de) + and 0F8h ; Clears previous value + or b + ld (de), a + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + and 0F8h ; Reset bits 0,1,2 sign to disable transparency + ld (de), a ; Store new attr + ret + + ; Sets the INK color passed in A register in the ATTR_T variable +INK_TMP: + ld de, ATTR_T + jp __SET_INK + + ENDP + +#line 10 "print.asm" +#line 1 "paper.asm" + + ; Sets paper color in ATTR_P permanently +; Parameter: Paper color in A register + + + +PAPER: + PROC + LOCAL __SET_PAPER + LOCAL __SET_PAPER2 + + ld de, ATTR_P + +__SET_PAPER: + cp 8 + jr nz, __SET_PAPER2 + inc de + ld a, (de) + or 038h + ld (de), a + ret + + ; Another entry. This will set the paper color at location pointer by DE +__SET_PAPER2: + and 7 ; # Remove + rlca + rlca + rlca ; a *= 8 + + ld b, a ; Saves the color + ld a, (de) + and 0C7h ; Clears previous value + or b + ld (de), a + inc de ; Points to MASK_T or MASK_P accordingly + ld a, (de) + and 0C7h ; Resets bits 3,4,5 + ld (de), a + ret + + + ; Sets the PAPER color passed in A register in the ATTR_T variable +PAPER_TMP: + ld de, ATTR_T + jp __SET_PAPER + ENDP + +#line 11 "print.asm" +#line 1 "flash.asm" + + ; Sets flash flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +FLASH: + ld de, ATTR_P +__SET_FLASH: + ; Another entry. This will set the flash flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + ld b, a ; Saves the color + ld a, (de) + and 07Fh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the FLASH flag passed in A register in the ATTR_T variable +FLASH_TMP: + ld de, ATTR_T + jr __SET_FLASH + +#line 12 "print.asm" +#line 1 "bright.asm" + + ; Sets bright flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +BRIGHT: + ld de, ATTR_P + +__SET_BRIGHT: + ; Another entry. This will set the bright flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + rrca + ld b, a ; Saves the color + ld a, (de) + and 0BFh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable +BRIGHT_TMP: + ld de, ATTR_T + jr __SET_BRIGHT + +#line 13 "print.asm" +#line 1 "over.asm" + + ; Sets OVER flag in P_FLAG permanently +; Parameter: OVER flag in bit 0 of A register +#line 1 "copy_attr.asm" + + + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" + + + +COPY_ATTR: + ; Just copies current permanent attribs to temporal attribs + ; and sets print mode + PROC + + LOCAL INVERSE1 + LOCAL __REFRESH_TMP + + INVERSE1 EQU 02Fh + + ld hl, (ATTR_P) + ld (ATTR_T), hl + + ld hl, FLAGS2 + call __REFRESH_TMP + + ld hl, P_FLAG + call __REFRESH_TMP + + +__SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) + + + LOCAL TABLE + LOCAL CONT2 + + rra ; Over bit to carry + ld a, (FLAGS2) + rla ; Over bit in bit 1, Over2 bit in bit 2 + and 3 ; Only bit 0 and 1 (OVER flag) + + ld c, a + ld b, 0 + + ld hl, TABLE + add hl, bc + ld a, (hl) + ld (PRINT_MODE), a + + ld hl, (P_FLAG) + xor a ; NOP -> INVERSE0 + bit 2, l + jr z, CONT2 + ld a, INVERSE1 ; CPL -> INVERSE1 + +CONT2: + ld (INVERSE_MODE), a + ret + +TABLE: + nop ; NORMAL MODE + xor (hl) ; OVER 1 MODE + and (hl) ; OVER 2 MODE + or (hl) ; OVER 3 MODE + +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" + +__REFRESH_TMP: + ld a, (hl) + and 10101010b + ld c, a + rra + or c + ld (hl), a + ret + + ENDP + +#line 4 "over.asm" + + +OVER: + PROC + + ld c, a ; saves it for later + and 2 + ld hl, FLAGS2 + res 1, (HL) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 ; # Convert to 0/1 + add a, a; # Shift left 1 bit for permanent + + ld hl, P_FLAG + res 1, (hl) + or (hl) + ld (hl), a + ret + + ; Sets OVER flag in P_FLAG temporarily +OVER_TMP: + ld c, a ; saves it for later + and 2 ; gets bit 1; clears carry + rra + ld hl, FLAGS2 + res 0, (hl) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 + ld hl, P_FLAG + res 0, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 14 "print.asm" +#line 1 "inverse.asm" + + ; Sets INVERSE flag in P_FLAG permanently +; Parameter: INVERSE flag in bit 0 of A register + + + +INVERSE: + PROC + + and 1 ; # Convert to 0/1 + add a, a; # Shift left 3 bits for permanent + add a, a + add a, a + ld hl, P_FLAG + res 3, (hl) + or (hl) + ld (hl), a + ret + + ; Sets INVERSE flag in P_FLAG temporarily +INVERSE_TMP: + and 1 + add a, a + add a, a; # Shift left 2 bits for temporary + ld hl, P_FLAG + res 2, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 15 "print.asm" +#line 1 "bold.asm" + + ; Sets BOLD flag in P_FLAG permanently +; Parameter: BOLD flag in bit 0 of A register + + +BOLD: + PROC + + and 1 + rlca + rlca + rlca + ld hl, FLAGS2 + res 3, (HL) + or (hl) + ld (hl), a + ret + + ; Sets BOLD flag in P_FLAG temporarily +BOLD_TMP: + and 1 + rlca + rlca + ld hl, FLAGS2 + res 2, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 16 "print.asm" +#line 1 "italic.asm" + + ; Sets ITALIC flag in P_FLAG permanently +; Parameter: ITALIC flag in bit 0 of A register + + +ITALIC: + PROC + + and 1 + rrca + rrca + rrca + ld hl, FLAGS2 + res 5, (HL) + or (hl) + ld (hl), a + ret + + ; Sets ITALIC flag in P_FLAG temporarily +ITALIC_TMP: + and 1 + rrca + rrca + rrca + rrca + ld hl, FLAGS2 + res 4, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 17 "print.asm" + +#line 1 "attr.asm" + + ; Attribute routines +; vim:ts=4:et:sw: + + + + + + + +__ATTR_ADDR: + ; calc start address in DE (as (32 * d) + e) + ; Contributed by Santiago Romero at http://www.speccy.org + ld h, 0 ; 7 T-States + ld a, d ; 4 T-States + add a, a ; a * 2 ; 4 T-States + add a, a ; a * 4 ; 4 T-States + ld l, a ; HL = A * 4 ; 4 T-States + + add hl, hl ; HL = A * 8 ; 15 T-States + add hl, hl ; HL = A * 16 ; 15 T-States + add hl, hl ; HL = A * 32 ; 15 T-States + + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) + add hl, de + + ld de, (SCREEN_ADDR) ; Adds the screen address + add hl, de + + ; Return current screen address in HL + ret + + + ; Sets the attribute at a given screen coordinate (D, E). + ; The attribute is taken from the ATTR_T memory variable + ; Used by PRINT routines +SET_ATTR: + + ; Checks for valid coords + call __IN_SCREEN + ret nc + +__SET_ATTR: + ; Internal __FASTCALL__ Entry used by printing routines + PROC + + call __ATTR_ADDR + ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T + + ld a, d + and (hl) + ld c, a ; C = current screen color, masked + + ld a, d + cpl ; Negate mask + and e ; Mask current attributes + or c ; Mix them + ld (hl), a ; Store result in screen + + ret + + ENDP + + +#line 19 "print.asm" + + ; Putting a comment starting with @INIT
+ ; will make the compiler to add a CALL to
+ ; It is useful for initialization routines. + + +__PRINT_INIT: ; To be called before program starts (initializes library) + PROC + + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + + ld hl, 1821h + ld (MAXX), hl ; Sets current maxX and maxY + + xor a + ld (FLAGS2), a + + ret + + +__PRINTCHAR: ; Print character store in accumulator (A register) + ; Modifies H'L', B'C', A'F', D'E', A + + LOCAL PO_GR_1 + + LOCAL __PRCHAR + LOCAL __PRINT_CONT + LOCAL __PRINT_CONT2 + LOCAL __PRINT_JUMP + LOCAL __SRCADDR + LOCAL __PRINT_UDG + LOCAL __PRGRAPH + LOCAL __PRINT_START + + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 + +__PRINT_JUMP: + jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively + +__PRINT_START: + cp ' ' + jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones + + exx ; Switch to alternative registers + ex af, af' ; Saves a value (char to print) for later + + call __LOAD_S_POSN + + ; At this point we have the new coord + ld hl, (SCREEN_ADDR) + + ld a, d + ld c, a ; Saves it for later + + and 0F8h ; Masks 3 lower bit ; zy + ld d, a + + ld a, c ; Recovers it + and 07h ; MOD 7 ; y1 + rrca + rrca + rrca + + or e + ld e, a + add hl, de ; HL = Screen address + DE + ex de, hl ; DE = Screen address + + ex af, af' + + cp 80h ; Is it an UDG or a ? + jp c, __SRCADDR + + cp 90h + jp nc, __PRINT_UDG + + ; Print a 8 bit pattern (80h to 8Fh) + + ld b, a + call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 + ld hl, MEM0 + jp __PRGRAPH + + PO_GR_1 EQU 0B38h + +__PRINT_UDG: + sub 90h ; Sub ASC code + ld bc, (UDG) + jp __PRGRAPH0 + + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source +__SRCADDR: + ld bc, (CHARS) + +__PRGRAPH0: + add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org + ld l, a + ld h, 0 ; HL = a * 2 (accumulator) + add hl, hl + add hl, hl ; HL = a * 8 + add hl, bc ; HL = CHARS address + +__PRGRAPH: + ex de, hl ; HL = Write Address, DE = CHARS address + bit 2, (iy + $47) + call nz, __BOLD + bit 4, (iy + $47) + call nz, __ITALIC + ld b, 8 ; 8 bytes per char +__PRCHAR: + ld a, (de) ; DE *must* be ALWAYS source, and HL destiny + +PRINT_MODE: ; Which operation is used to write on the screen + ; Set it with: + ; LD A, + ; LD (PRINT_MODE), A + ; + ; Available opertions: + ; NORMAL: 0h --> NOP ; OVER 0 + ; XOR : AEh --> XOR (HL) ; OVER 1 + ; OR : B6h --> OR (HL) ; PUTSPRITE + ; AND : A6h --> AND (HL) ; PUTMASK + nop ; + +INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 + nop ; 2F -> CPL -> INVERSE 1 + + ld (hl), a + + inc de + inc h ; Next line + djnz __PRCHAR + + call __LOAD_S_POSN + push de + call __SET_ATTR + pop de + inc e ; COL = COL + 1 + ld hl, (MAXX) + ld a, e + dec l ; l = MAXX + cp l ; Lower than max? + jp c, __PRINT_CONT; Nothing to do + call __PRINT_EOL1 + exx ; counteracts __PRINT_EOL1 exx + jp __PRINT_CONT2 + +__PRINT_CONT: + call __SAVE_S_POSN + +__PRINT_CONT2: + exx + ret + + ; ------------- SPECIAL CHARS (< 32) ----------------- + +__PRINT_SPECIAL: ; Jumps here if it is a special char + exx + ld hl, __PRINT_TABLE + jp JUMP_HL_PLUS_2A + + +PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence + exx + +__PRINT_0Dh: ; Called WHEN printing CHR$(13) + call __LOAD_S_POSN + +__PRINT_EOL1: ; Another entry called from PRINT when next line required + ld e, 0 + +__PRINT_EOL2: + ld a, d + inc a + +__PRINT_AT1_END: + ld hl, (MAXY) + cp l + jr c, __PRINT_EOL_END ; Carry if (MAXY) < d + xor a + +__PRINT_EOL_END: + ld d, a + +__PRINT_AT2_END: + call __SAVE_S_POSN + exx + ret + +__PRINT_COM: + exx + push hl + push de + push bc + call PRINT_COMMA + pop bc + pop de + pop hl + ret + +__PRINT_TAB: + ld hl, __PRINT_TAB1 + jp __PRINT_SET_STATE + +__PRINT_TAB1: + ld (MEM0), a + ld hl, __PRINT_TAB2 + ld (PRINT_JUMP_STATE), hl + ret + +__PRINT_TAB2: + ld a, (MEM0) ; Load tab code (ignore the current one) + push hl + push de + push bc + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + call PRINT_TAB + pop bc + pop de + pop hl + ret + +__PRINT_NOP: +__PRINT_RESTART: + ld hl, __PRINT_START + jp __PRINT_SET_STATE + +__PRINT_AT: + ld hl, __PRINT_AT1 + +__PRINT_SET_STATE: + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + exx + ret + +__PRINT_AT1: ; Jumps here if waiting for 1st parameter + exx + ld hl, __PRINT_AT2 + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + jp __PRINT_AT1_END + +__PRINT_AT2: + exx + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + ld e, a + ld hl, (MAXX) + cp (hl) + jr c, __PRINT_AT2_END + jr __PRINT_EOL1 + +__PRINT_DEL: + call __LOAD_S_POSN ; Gets current screen position + dec e + ld a, -1 + cp e + jp nz, __PRINT_AT2_END + ld hl, (MAXX) + ld e, l + dec e + dec e + dec d + cp d + jp nz, __PRINT_AT2_END + ld d, h + dec d + jp __PRINT_AT2_END + +__PRINT_INK: + ld hl, __PRINT_INK2 + jp __PRINT_SET_STATE + +__PRINT_INK2: + exx + call INK_TMP + jp __PRINT_RESTART + +__PRINT_PAP: + ld hl, __PRINT_PAP2 + jp __PRINT_SET_STATE + +__PRINT_PAP2: + exx + call PAPER_TMP + jp __PRINT_RESTART + +__PRINT_FLA: + ld hl, __PRINT_FLA2 + jp __PRINT_SET_STATE + +__PRINT_FLA2: + exx + call FLASH_TMP + jp __PRINT_RESTART + +__PRINT_BRI: + ld hl, __PRINT_BRI2 + jp __PRINT_SET_STATE + +__PRINT_BRI2: + exx + call BRIGHT_TMP + jp __PRINT_RESTART + +__PRINT_INV: + ld hl, __PRINT_INV2 + jp __PRINT_SET_STATE + +__PRINT_INV2: + exx + call INVERSE_TMP + jp __PRINT_RESTART + +__PRINT_OVR: + ld hl, __PRINT_OVR2 + jp __PRINT_SET_STATE + +__PRINT_OVR2: + exx + call OVER_TMP + jp __PRINT_RESTART + +__PRINT_BOLD: + ld hl, __PRINT_BOLD2 + jp __PRINT_SET_STATE + +__PRINT_BOLD2: + exx + call BOLD_TMP + jp __PRINT_RESTART + +__PRINT_ITA: + ld hl, __PRINT_ITA2 + jp __PRINT_SET_STATE + +__PRINT_ITA2: + exx + call ITALIC_TMP + jp __PRINT_RESTART + + +__BOLD: + push hl + ld hl, MEM0 + ld b, 8 +__BOLD_LOOP: + ld a, (de) + ld c, a + rlca + or c + ld (hl), a + inc hl + inc de + djnz __BOLD_LOOP + pop hl + ld de, MEM0 + ret + + +__ITALIC: + push hl + ld hl, MEM0 + ex de, hl + ld bc, 8 + ldir + ld hl, MEM0 + srl (hl) + inc hl + srl (hl) + inc hl + srl (hl) + inc hl + inc hl + inc hl + sla (hl) + inc hl + sla (hl) + inc hl + sla (hl) + pop hl + ld de, MEM0 + ret + +PRINT_COMMA: + call __LOAD_S_POSN + ld a, e + and 16 + add a, 16 + +PRINT_TAB: + PROC + LOCAL LOOP, CONTINUE + + inc a + call __LOAD_S_POSN ; e = current row + ld d, a + ld a, e + cp 21h + jr nz, CONTINUE + ld e, -1 +CONTINUE: + ld a, d + inc e + sub e ; A = A - E + and 31 ; + ret z ; Already at position E + ld b, a +LOOP: + ld a, ' ' + call __PRINTCHAR + djnz LOOP + ret + ENDP + +PRINT_AT: ; CHanges cursor to ROW, COL + ; COL in A register + ; ROW in stack + + pop hl ; Ret address + ex (sp), hl ; callee H = ROW + ld l, a + ex de, hl + + call __IN_SCREEN + ret nc ; Return if out of screen + + jp __SAVE_S_POSN + + LOCAL __PRINT_COM + LOCAL __BOLD + LOCAL __BOLD_LOOP + LOCAL __ITALIC + LOCAL __PRINT_EOL1 + LOCAL __PRINT_EOL2 + LOCAL __PRINT_AT1 + LOCAL __PRINT_AT2 + LOCAL __PRINT_AT2_END + LOCAL __PRINT_BOLD + LOCAL __PRINT_BOLD2 + LOCAL __PRINT_ITA + LOCAL __PRINT_ITA2 + LOCAL __PRINT_INK + LOCAL __PRINT_PAP + LOCAL __PRINT_SET_STATE + LOCAL __PRINT_TABLE + LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 + +__PRINT_TABLE: ; Jump table for 0 .. 22 codes + + DW __PRINT_NOP ; 0 + DW __PRINT_NOP ; 1 + DW __PRINT_NOP ; 2 + DW __PRINT_NOP ; 3 + DW __PRINT_NOP ; 4 + DW __PRINT_NOP ; 5 + DW __PRINT_COM ; 6 COMMA + DW __PRINT_NOP ; 7 + DW __PRINT_DEL ; 8 DEL + DW __PRINT_NOP ; 9 + DW __PRINT_NOP ; 10 + DW __PRINT_NOP ; 11 + DW __PRINT_NOP ; 12 + DW __PRINT_0Dh ; 13 + DW __PRINT_BOLD ; 14 + DW __PRINT_ITA ; 15 + DW __PRINT_INK ; 16 + DW __PRINT_PAP ; 17 + DW __PRINT_FLA ; 18 + DW __PRINT_BRI ; 19 + DW __PRINT_INV ; 20 + DW __PRINT_OVR ; 21 + DW __PRINT_AT ; 22 AT + DW __PRINT_TAB ; 23 TAB + + ENDP + + +#line 99 "opt3_data2.bas" +#line 1 "printu8.asm" + +#line 1 "printi8.asm" + +#line 1 "printnum.asm" + + + + +__PRINTU_START: + PROC + + LOCAL __PRINTU_CONT + + ld a, b + or a + jp nz, __PRINTU_CONT + + ld a, '0' + jp __PRINT_DIGIT + + +__PRINTU_CONT: + pop af + push bc + call __PRINT_DIGIT + pop bc + djnz __PRINTU_CONT + ret + + ENDP + + +__PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers + ld a, '-' + jp __PRINT_DIGIT + + __PRINT_DIGIT EQU __PRINTCHAR ; PRINTS the char in A register, and puts its attrs + + +#line 2 "printi8.asm" +#line 1 "div8.asm" + + ; -------------------------------- +__DIVU8: ; 8 bit unsigned integer division + ; Divides (Top of stack, High Byte) / A + pop hl ; -------------------------------- + ex (sp), hl ; CALLEE + +__DIVU8_FAST: ; Does A / H + ld l, h + ld h, a ; At this point do H / L + + ld b, 8 + xor a ; A = 0, Carry Flag = 0 + +__DIV8LOOP: + sla h + rla + cp l + jr c, __DIV8NOSUB + sub l + inc h + +__DIV8NOSUB: + djnz __DIV8LOOP + + ld l, a ; save remainder + ld a, h ; + + ret ; a = Quotient, + + + ; -------------------------------- +__DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A + pop hl ; -------------------------------- + ex (sp), hl + +__DIVI8_FAST: + ld e, a ; store operands for later + ld c, h + + or a ; negative? + jp p, __DIV8A + neg ; Make it positive + +__DIV8A: + ex af, af' + ld a, h + or a + jp p, __DIV8B + neg + ld h, a ; make it positive + +__DIV8B: + ex af, af' + + call __DIVU8_FAST + + ld a, c + xor l ; bit 7 of A = 1 if result is negative + + ld a, h ; Quotient + ret p ; return if positive + + neg + ret + + +__MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) + pop hl + ex (sp), hl ; CALLEE + +__MODU8_FAST: ; __FASTCALL__ entry + call __DIVU8_FAST + ld a, l ; Remainder + + ret ; a = Modulus + + +__MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) + pop hl + ex (sp), hl ; CALLEE + +__MODI8_FAST: ; __FASTCALL__ entry + call __DIVI8_FAST + ld a, l ; remainder + + ret ; a = Modulus + +#line 3 "printi8.asm" + +__PRINTI8: ; Prints an 8 bits number in Accumulator (A) + ; Converts 8 to 32 bits + or a + jp p, __PRINTU8 + + push af + call __PRINT_MINUS + pop af + neg + +__PRINTU8: + PROC + + LOCAL __PRINTU_LOOP + + ld b, 0 ; Counter + +__PRINTU_LOOP: + or a + jp z, __PRINTU_START + + push bc + ld h, 10 + call __DIVU8_FAST ; Divides by 10. D'E'H'L' contains modulo (L' since < 10) + pop bc + + ld a, l + or '0' ; Stores ASCII digit (must be print in reversed order) + push af + ld a, h + inc b + jp __PRINTU_LOOP ; Uses JP in loops + + ENDP + +#line 2 "printu8.asm" + +#line 100 "opt3_data2.bas" +#line 1 "read_restore.asm" + + ;; This implements READ & RESTORE functions + ;; Reads a new element from the DATA Address code + ;; Updates the DATA_ADDR read ptr for the next read + + ;; Data codification is 1 byte for type followed by data bytes + ;; Byte type is encoded as follows + +;; 00: End of data +;; 01: String +;; 02: Byte +;; 03: Ubyte +;; 04: Integer +;; 05: UInteger +;; 06: Long +;; 07: ULong +;; 08: Fixed +;; 09: Float + + ;; bit7 is set for a parameter-less function + ;; In that case, the next two bytes are the ptr of the function to jump + + +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 70 "alloc.asm" + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 24 "read_restore.asm" +#line 1 "iload32.asm" + + ; __FASTCALL__ routine which + ; loads a 32 bits integer into DE,HL + ; stored at position pointed by POINTER HL + ; DE,HL <-- (HL) + +__ILOAD32: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + ex de, hl + ret + +#line 25 "read_restore.asm" +#line 1 "iloadf.asm" + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- ((HL)) + +__ILOADF: + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- (HL) + +__LOADF: ; Loads a 40 bits FP number from address pointed by HL + ld a, (hl) + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld c, (hl) + inc hl + ld b, (hl) + ret + +#line 26 "read_restore.asm" +#line 1 "ftof16reg.asm" + +#line 1 "ftou32reg.asm" + +#line 1 "neg32.asm" + +__ABS32: + bit 7, d + ret z + +__NEG32: ; Negates DEHL (Two's complement) + ld a, l + cpl + ld l, a + + ld a, h + cpl + ld h, a + + ld a, e + cpl + ld e, a + + ld a, d + cpl + ld d, a + + inc l + ret nz + + inc h + ret nz + + inc de + ret + +#line 2 "ftou32reg.asm" + +__FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + ; Output: DEHL 32 bit number (signed) + PROC + + LOCAL __IS_FLOAT + + or a + jr nz, __IS_FLOAT + ; Here if it is a ZX ROM Integer + + ld h, c + ld l, d + ld a, e ; Takes sign: FF = -, 0 = + + ld de, 0 + inc a + jp z, __NEG32 ; Negates if negative + ret + +__IS_FLOAT: ; Jumps here if it is a true floating point number + ld h, e + push hl ; Stores it for later (Contains Sign in H) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + ;ld a, c ; Get exponent + sub 128 ; Exponent -= 128 + jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + +__FTOU32REG_LOOP: + exx ; Shift C'B' E'D' << 1, output bit stays in Carry + sla d + rl e + rl b + rl c + + exx ; Shift DEHL << 1, inserting the carry on the right + rl l + rl h + rl e + rl d + + djnz __FTOU32REG_LOOP + +__FTOU32REG_END: + pop af ; Take the sign bit + or a ; Sets SGN bit to 1 if negative + jp m, __NEG32 ; Negates DEHL + + ret + + ENDP + + +__FTOU8: ; Converts float in C ED LH to Unsigned byte in A + call __FTOU32REG + ld a, l + ret + +#line 2 "ftof16reg.asm" + +__FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + + ld l, a ; Saves exponent for later + or d + or e + or b + or c + ld h, e + ret z ; Return if ZERO + + push hl ; Stores it for later (Contains sign in H, exponent in L) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + pop bc + + ld a, c ; Get exponent + sub 112 ; Exponent -= 128 + 16 + + push bc ; Saves sign in b again + + jp z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jp c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + 16 (we need to shift 16 bit more) + jp __FTOU32REG_LOOP ; proceed as an u32 integer + +#line 27 "read_restore.asm" +#line 1 "f16tofreg.asm" + + +#line 1 "u32tofreg.asm" + + +__I8TOFREG: + ld l, a + rlca + sbc a, a ; A = SGN(A) + ld h, a + ld e, a + ld d, a + +__I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) + ; to a Floating Point Number returned in (A ED CB) + + ld a, d + or a ; Test sign + + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __U32TOFREG ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + +__U8TOFREG: + ; Converts an unsigned 8 bit (A) to Floating point + ld l, a + ld h, 0 + ld e, h + ld d, h + +__U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in A ED CB + + PROC + + LOCAL __U32TOFREG_END + + ld a, d + or e + or h + or l + ld b, d + ld c, e ; Returns 00 0000 0000 if ZERO + ret z + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 128 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + +__U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG + exx + ld a, d ; B'C'D'E' == 0 ? + or e + or b + or c + jp z, __U32TOFREG_END ; We are done + + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry + rr c + rr d + rr e + exx + + rr e ; Shift EDCB >> 1, inserting the carry on the left + rr d + rr c + rr b + + inc l ; Increment exponent + jp __U32TOFREG_LOOP + + +__U32TOFREG_END: + exx + ld a, l ; Puts the exponent in a + res 7, e ; Sets the sign bit to 0 (positive) + + ret + ENDP + +#line 3 "f16tofreg.asm" + +__F16TOFREG: ; Converts a 16.16 signed fixed point (stored in DEHL) + ; to a Floating Point Number returned in (C ED CB) + PROC + + LOCAL __F16TOFREG2 + + ld a, d + or a ; Test sign + + jp p, __F16TOFREG2 ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __F16TOFREG2 ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + + +__F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in C DE HL + + ld a, d + or e + or h + or l + ld b, h + ld c, l + ret z ; Return 00 0000 0000 if 0 + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 112 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + jp __U32TOFREG_LOOP ; Proceed as an integer + + ENDP + +#line 28 "read_restore.asm" +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 29 "read_restore.asm" + + + + + + + + + + + + + ;; Updates restore point to the given HL mem. address +__RESTORE: + PROC + LOCAL __DATA_ADDR + + ld (__DATA_ADDR), hl + ret + + ;; Reads a value from the DATA mem area and updates __DATA_ADDR ptr to the + ;; next item. On Out Of Data, restarts + ;; +__READ: + LOCAL read_restart, cont, cont2, table, no_func + LOCAL dynamic_cast, dynamic_cast2, dynamic_cast3, dynamic_cast4 + LOCAL _decode_table, coerce_to_int, coerce_to_int2, promote_to_i16 + LOCAL _from_i8, _from_u8 + LOCAL _from_i16, _from_u16 + LOCAL _from_i32, _from_u32 + LOCAL _from_fixed, __data_error + + push af ; type of data to read + ld hl, (__DATA_ADDR) +read_restart: + ld a, (hl) + or a ; 0 => OUT of data + jr nz, cont + ;; Signals out of data + + ld hl, __DATA__0 + ld (__DATA_ADDR), hl + jr read_restart ; Start again +cont: + and 0x80 + ld a, (hl) + push af + jp z, no_func ;; Loads data directly, not a function + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl +cont2: + ld de, dynamic_cast + push de ; ret address + jp (hl) ; "call (hl)" + + ;; Now tries to convert the given result to the expected type or raise an error +dynamic_cast: + exx + ex af, af' + pop af ; type READ + and 0x7F ; clear bit 7 + pop hl ; type requested by USER (type of the READ variable) + ld c, h ; save requested type (save it in register C) + cp h + exx + jr nz, dynamic_cast2 ; Types are identical? + ;; yes, they are + ex af, af' + ret + +dynamic_cast2: + cp 1 ; Requested a number, but read a string? + jr nz, dynamic_cast3 + call __MEM_FREE ; Frees str from memory + jr __data_error + +dynamic_cast3: + exx + ld b, a ; Read type + ld a, c ; Requested type + cp 1 + jr z, __data_error + cp b + jr c, dynamic_cast4 + ;; here the user expected type is "larger" than the read one + ld a, b + sub 2 + add a, a + ld l, a + ld h, 0 + ld de, _decode_table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl + ld a, c ; Requested type + exx + ret + +__data_error: + ;; When a data is read, but cannot be converted to the requested type + ;; that is, the user asked for a string and we read a number or vice versa + ld a, ERROR_InvalidArg + call __STOP ; The user expected a string, but read a number + xor a + ld h, a + ld l, a + ld e, a + ld d, a + ld b, a + ld c, a + ret + +_decode_table: + dw _from_i8 + dw _from_u8 + dw _from_i16 + dw _from_u16 + dw _from_i32 + dw _from_u32 + dw _from_fixed + +_from_i8: + cp 4 + jr nc, promote_to_i16 + ex af, af' + ret ;; Was from Byte to Ubyte + +promote_to_i16: + ex af, af' + ld l, a + rla + sbc a, a + ld h, a ; copy sgn to h + ex af, af' + jr _before_from_i16 + +_from_u8: + ex af, af' + ld l, a + ld h, 0 + ex af, af' + ;; Promoted to i16 + +_before_from_i16: +_from_i16: + cp 6 + ret c ;; from i16 to u16 + ;; Promote i16 to i32 + ex af, af' + ld a, h + rla + sbc a, a + ld e, a + ld d, a + ex af, af' +_from_i32: + cp 7 + ret z ;; From i32 to u32 + ret c ;; From u16 to i32 + cp 9 + jp z, __I32TOFREG +_from_u32: + cp 9 + jp z, __U32TOFREG + ex de, hl + ld hl, 0 + cp 8 + ret z +_from_fixed: ;; From fixed to float + jp __F16TOFREG +_from_u16: + ld de, 0 ; HL 0x0000 => 32 bits + jp _from_i32 + +dynamic_cast4: + ;; The user type is "shorter" than the read one + cp 8 ;; required type + jr c, before_to_int ;; required < fixed (f16) + ex af, af' + exx ;; Ok, we must convert from float to f16 + jp __FTOF16REG + +before_to_int: + ld a, b ;; read type + cp 8 ;; + jr nz, coerce_to_int ;; From float to int + ld a, c ;; user type + exx + ;; f16 to Long + ex de, hl + ld a, h + rla + sbc a, a + ld d, a + ld e, a + exx + jr coerce_to_int2 +coerce_to_int: + exx + ex af, af' + call __FTOU32REG + ex af, af' ; a contains user type + exx +coerce_to_int2: ; At this point we have an u/integer in hl + exx + cp 4 + ret nc ; Already done. Return the result + ld a, l ; Truncate to byte + ret + +no_func: + exx + ld de, dynamic_cast + push de ; Ret address + dec a ; 0 => string; 1, 2 => byte; 3, 4 => integer; 5, 6 => long, 7 => fixed; 8 => float + ld h, 0 + add a, a + ld l, a + ld de, table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl ; address to jump to + exx + inc hl + ret ; jp (sp) => jump to table[a - 1] + +table: + LOCAL __01_decode_string + LOCAL __02_decode_byte + LOCAL __03_decode_ubyte + LOCAL __04_decode_integer + LOCAL __05_decode_uinteger + LOCAL __06_decode_long + LOCAL __07_decode_ulong + LOCAL __08_decode_fixed + LOCAL __09_decode_float + + ;; 1 -> Decode string + ;; 2, 3 -> Decode Byte, UByte + ;; 4, 5 -> Decode Integer, UInteger + ;; 6, 7 -> Decode Long, ULong + ;; 8 -> Decode Fixed + ;; 9 -> Decode Float + dw __01_decode_string + dw __02_decode_byte + dw __03_decode_ubyte + dw __04_decode_integer + dw __05_decode_uinteger + dw __06_decode_long + dw __07_decode_ulong + dw __08_decode_fixed + dw __09_decode_float + +__01_decode_string: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl + jp __LOADSTR + +__02_decode_byte: +__03_decode_ubyte: + ld a, (hl) + inc hl + ld (__DATA_ADDR), hl + ret + +__04_decode_integer: +__05_decode_uinteger: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl + ex de, hl + ret + +__06_decode_long: +__07_decode_ulong: +__08_decode_fixed: + ld b, h + ld c, l + inc bc + inc bc + inc bc + inc bc + ld (__DATA_ADDR), bc + jp __ILOAD32 + +__09_decode_float: + call __LOADF + inc hl + ld (__DATA_ADDR), hl + ld h, a ; returns A in H; sets A free + ret + +__DATA_ADDR: ;; Stores current DATA ptr + dw __DATA__0 + ENDP + + + + + + + + + + +#line 101 "opt3_data2.bas" + +ZXBASIC_USER_DATA: +_i: + DEFB 00 +_a: + DEFW 0000h + DEFB 01h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/opt3_data2.bas b/tests/functional/opt3_data2.bas new file mode 100644 index 000000000..a9e1aa7f1 --- /dev/null +++ b/tests/functional/opt3_data2.bas @@ -0,0 +1,11 @@ +DIM a(9) AS UBYTE + +FOR i = 0 TO 9: REM 0 TO 9 => 10 elements + READ a(i) + PRINT a(i) +NEXT i + +REM notice the a * a expression +DATA 2, 4, 6 * i, 7, 0 +DATA a(0), a(1), a(2), a(3), a(4) + From 274c7e3c0a2fd6320b1fffbbfd114985c34df80b Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 13 Oct 2017 00:15:49 +0200 Subject: [PATCH 080/247] refact: state selection Changes state selection in zxbpp lexer. This is slightly faster an cleaner. --- zxbasmpplex.py | 3 +-- zxbpplex.py | 24 +++++++++++------------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/zxbasmpplex.py b/zxbasmpplex.py index 756570207..b659e2d45 100755 --- a/zxbasmpplex.py +++ b/zxbasmpplex.py @@ -151,8 +151,7 @@ def t_prepro_ID(self, t): t.type = reserved_directives.get(t.value.lower(), 'ID') if t.type == 'DEFINE': t.lexer.begin('define') - - if t.type == 'PRAGMA': + elif t.type == 'PRAGMA': t.lexer.begin('pragma') return t diff --git a/zxbpplex.py b/zxbpplex.py index 223a4f418..55388bf35 100755 --- a/zxbpplex.py +++ b/zxbpplex.py @@ -223,19 +223,17 @@ def t_if_LT(self, t): def t_prepro_ID(self, t): r'[_a-zA-Z][_a-zA-Z0-9]*' # preprocessor directives t.type = reserved_directives.get(t.value.lower(), 'ID') - if t.type == 'DEFINE': - t.lexer.begin('define') - - if t.type == 'PRAGMA': - t.lexer.begin('pragma') - - if t.type == 'IF': - t.lexer.begin('if') - - if t.type in ('ERROR', 'WARNING'): - t.lexer.begin('msg') - - if t.type == 'ID' and self.expectingDirective: + states_ = { + 'DEFINE': 'define', + 'PRAGMA': 'pragma', + 'IF': 'if', + 'ERROR': 'msg', + 'WARNING': 'msg' + } + + if t.type in states_: + t.lexer.begin(states_[t.type]) + elif t.type == 'ID' and self.expectingDirective: self.error("invalid directive #%s" % t.value) self.expectingDirective = False From 8034c9e58e0ca69cc970b0ede34c3625b0d4ca74 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 13 Oct 2017 00:32:47 +0200 Subject: [PATCH 081/247] update some readme files --- ChangeLog | 6 ++++++ README.md | 29 +++++++++++++++-------------- TESTING.md | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 14 deletions(-) create mode 100644 TESTING.md diff --git a/ChangeLog b/ChangeLog index f5df99884..b3b614ea8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +================================================================ +Changes from Version 1.7.0 to 1.7.1 +! Bugfixes with -O3 and DATA statements +* Little improvements +* Updates README.md and added TESTING.md + ================================================================ Changes from Version 1.6.13 to 1.7.0 + Added READ, DATA, RESTORE (finally!) diff --git a/README.md b/README.md index e91f0e742..99eea23c4 100644 --- a/README.md +++ b/README.md @@ -44,29 +44,30 @@ For Windows users there is also a binary .MSI installation, which does not need python installed. -TESTING -------- +QUICK START +----------- + +For a quick start, just open a terminal in your PC (Windows) and type +`zxb` or `zxb.py` (OSX, Linux). You should see a zxbasic message. -You will need to get Tox in order to run the project tests. Normally it is done -by calling: +Create a text file, `hello.bas` with the following content: ~~~~ -$ pip install tox +10 CLS +20 PRINT "HELLO WORLD!" ~~~~ -inside a Virtual Environment ( https://virtualenv.pypa.io/en/stable/ ). - -Please, see https://tox.readthedocs.io/en/latest/install.html for more -information about installing Tox. - -Once you have installed Tox, just call: - +and compile it with: ~~~~ -$ tox +zxb -taB hello.bas ~~~~ -to get your tests running. +If everything went well, a file named `hello.tap` should be created. +Open it with your favourite emulator (i.e. fuse) and see the result. +Congratulations! You're now ready to create compiled BASIC programs for +your machine. Check and compile the examples included in the examples/ folder +or go to the Wiki for further info. AKNOWLEDGEMENTS --------------- diff --git a/TESTING.md b/TESTING.md new file mode 100644 index 000000000..6f4251daf --- /dev/null +++ b/TESTING.md @@ -0,0 +1,32 @@ +TESTING +------- + +This instructions are for TDD (Test Drive Development) the compiler and are intended +for developing the compiler internals, and checks for bugs in it. + +You **DONT** need to do this to compile BASIC. + +You are required to be familiar not only with python, but also with the python +ecosystem (virtualenvs, tox, py.test). + +You will need to get Tox in order to run the project tests. Normally it is done +by calling: + +~~~~ +$ pip install tox +~~~~ + +Inside a Virtual Environment of your choice ( https://virtualenv.pypa.io/en/stable/ ). + +Please, see https://tox.readthedocs.io/en/latest/install.html for more +information about installing Tox. + +Once you have installed Tox, just call: + +~~~~ +$ tox +~~~~ + +to get your tests running. + +This tox config also supports detox (parallel tox testing). \ No newline at end of file From 81a94adfcee35982234ca292524c01001de36604 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 13 Oct 2017 00:33:18 +0200 Subject: [PATCH 082/247] =?UTF-8?q?Bump=20version:=201.7.0=20=E2=86=92=201?= =?UTF-8?q?.7.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index f67999c50..d7411a512 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,4 +1,4 @@ [bumpversion] -current_version = 1.7.0 +current_version = 1.7.1 files = version.py diff --git a/version.py b/version.py index 81af48306..f4dc8dec6 100755 --- a/version.py +++ b/version.py @@ -1 +1 @@ -VERSION = '1.7.0' +VERSION = '1.7.1' From 9cf0aa058f2034ddc1cd469287f8ee883b01701e Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 13 Oct 2017 18:05:23 +0200 Subject: [PATCH 083/247] normalize namespace mangling All namespaces must begin with ".". This scheme is similar of that of filesystem directories with "/" but using a dot. --- asmlex.py | 5 +-- asmparse.py | 79 ++++++++++++++++++--------------- tests/functional/asmproc04.asm | 2 +- tests/functional/asmproc06a.asm | 4 +- 4 files changed, 49 insertions(+), 41 deletions(-) diff --git a/asmlex.py b/asmlex.py index df66da78c..f53fdea3b 100755 --- a/asmlex.py +++ b/asmlex.py @@ -109,8 +109,7 @@ 'local': 'LOCAL', 'end': 'END', 'incbin': 'INCBIN', - 'namespace': 'NAMESPACE', - 'default': 'DEFAULT' + 'namespace': 'NAMESPACE' } regs8 = {'a': 'A', @@ -245,7 +244,7 @@ def t_INITIAL_preproc_INTEGER(self, t): return t def t_INITIAL_ID(self, t): - r'[.]?[_a-zA-Z]([.]?[_a-zA-Z0-9]+)*[:]?' # Any identifier + r'[._a-zA-Z]([._a-zA-Z0-9]+)*[:]?' # Any identifier tmp = t.value # Saves original value if tmp[-1] == ':': diff --git a/asmparse.py b/asmparse.py index 9ee8ee8ce..0d645ccf0 100755 --- a/asmparse.py +++ b/asmparse.py @@ -12,6 +12,7 @@ # ---------------------------------------------------------------------- import os +import re import asmlex import ply.yacc as yacc @@ -32,6 +33,7 @@ INITS = [] MEMORY = None # Memory for instructions (Will be initialized with a Memory() instance) AUTORUN_ADDR = None # Where to start the execution automatically +RE_DOTS = re.compile(r'\.+') REGS16 = ('BC', 'DE', 'HL', 'SP', 'IX', 'IY') # 16 Bits registers REGS8 = ('A', 'B', 'C', 'D', 'E', 'H', 'L', 'IXh', 'IXl', 'IYh', 'IYl') @@ -46,7 +48,20 @@ MAX_MEM = 65535 # Max memory limit DOT = '.' # NAMESPACE separator -NAMESPACE = '' # Current namespace (defaults to ''). It's a prefix added to each global label +GLOBAL_NAMESPACE = DOT +NAMESPACE = GLOBAL_NAMESPACE # Current namespace (defaults to ''). It's a prefix added to each global label + + +def normalize_namespace(namespace): + """ Given a namespace (e.g. '.' or 'mynamespace'), + returns it in normalized form. That is: + - always prefixed with a dot + - no trailing dots + - any double dots are converted to single dot (..my..namespace => .my.namespace) + - one or more dots (e.g. '.', '..', '...') are converted to '.' (Global namespace) + """ + namespace = (DOT + DOT.join(RE_DOTS.split(namespace))).rstrip(DOT) + DOT + return namespace def init(): @@ -63,7 +78,7 @@ def init(): INITS = [] MEMORY = None # Memory for instructions (Will be initialized with a Memory() instance) AUTORUN_ADDR = None # Where to start the execution automatically - NAMESPACE = '' # Current namespace (defaults to ''). It's a prefix added to each global label + NAMESPACE = GLOBAL_NAMESPACE # Current namespace (defaults to ''). It's a prefix added to each global label gl.has_errors = 0 @@ -330,10 +345,7 @@ def resolve(self, lineno): @property def name(self): - if self.namespace is not None: - return self.namespace + self._name - - return self.current_namespace + self._name + return self._name class Memory(object): @@ -366,6 +378,23 @@ def set_org(self, value, lineno): self.index = self.ORG = value + @staticmethod + def id_name(label, namespace=None): + """ Given a name and a namespace, resolves + returns the name as namespace + '.' + name. If namespace + is none, the current NAMESPACE is used + """ + if not label.startswith(DOT): + if namespace is None: + namespace = NAMESPACE + ex_label = namespace + label # The mangled namespace.labelname label + else: + if namespace is None: + namespace = GLOBAL_NAMESPACE # Global namespace + ex_label = label + + return ex_label, namespace + @property def org(self): """ Returns current ORG index @@ -476,14 +505,7 @@ def declare_label(self, label, lineno, value=None, local=False, namespace=None): Exits with error if label already set, otherwise return the label object """ - if label[0] != DOT: - if namespace is None: - namespace = NAMESPACE - ex_label = namespace + label # The mangled namespace.labelname label - else: - if namespace is None: - namespace = '' # Global namespace - ex_label = label = label[len(DOT):] + ex_label, namespace = Memory.id_name(label, namespace) is_address = value is None if value is None: @@ -493,7 +515,7 @@ def declare_label(self, label, lineno, value=None, local=False, namespace=None): self.local_labels[-1][ex_label].define(value, lineno) self.local_labels[-1][ex_label].is_address = is_address else: - self.local_labels[-1][ex_label] = Label(label, lineno, value, local, namespace, is_address) + self.local_labels[-1][ex_label] = Label(ex_label, lineno, value, local, namespace, is_address) self.set_memory_slot() self.memory_bytes[self.org] += ('%s:' % ex_label,) @@ -506,19 +528,14 @@ def get_label(self, label, lineno): """ global NAMESPACE - if label[0] != DOT: - ex_label = NAMESPACE + label # expanded name - namespace = NAMESPACE - else: - ex_label = label = label[len(DOT):] - namespace = '' + ex_label, namespace = Memory.id_name(label) for i in range(len(self.local_labels) - 1, -1, -1): # Downstep result = self.local_labels[i].get(ex_label, None) if result is not None: return result - result = Label(label, lineno, namespace=namespace) + result = Label(ex_label, lineno, namespace=namespace) self.local_labels[-1][ex_label] = result # HINT: no namespace return result @@ -530,16 +547,13 @@ def set_label(self, label, lineno, local=False): The resulting label is returned. """ - if label[0] != DOT: - ex_label = NAMESPACE + label # expanded name - else: - ex_label = label = label[len(DOT):] + ex_label, namespace = Memory.id_name(label) if ex_label in self.local_labels[-1].keys(): result = self.local_labels[-1][ex_label] result.lineno = lineno else: - result = self.local_labels[-1][ex_label] = Label(label, lineno, namespace=NAMESPACE) + result = self.local_labels[-1][ex_label] = Label(ex_label, lineno, namespace=NAMESPACE) if result.local == local: warning(lineno, "label '%s' already declared as LOCAL" % label) @@ -803,17 +817,12 @@ def p_org(p): def p_namespace(p): - """ asm : NAMESPACE DEFAULT - | NAMESPACE ID + """ asm : NAMESPACE ID """ global NAMESPACE - if p[2] != 'DEFAULT': - NAMESPACE = p[2] + '.' - else: - NAMESPACE = '' - - __DEBUG__('Setting namespace to ' + NAMESPACE, level=1) + NAMESPACE = normalize_namespace(p[2]) + __DEBUG__('Setting namespace to ' + (NAMESPACE.rstrip(DOT) or DOT), level=1) def p_align(p): diff --git a/tests/functional/asmproc04.asm b/tests/functional/asmproc04.asm index b29b255cb..e10c6a742 100644 --- a/tests/functional/asmproc04.asm +++ b/tests/functional/asmproc04.asm @@ -5,7 +5,7 @@ testLabel: NAMESPACE other anotherTest: -Namespace default +Namespace . jp test.testLabel diff --git a/tests/functional/asmproc06a.asm b/tests/functional/asmproc06a.asm index 77e396f61..d3499663a 100644 --- a/tests/functional/asmproc06a.asm +++ b/tests/functional/asmproc06a.asm @@ -1,5 +1,5 @@ -; This label should be used in favour of the local one +; The first testLlabel should be used in favour of the local one ; because the jp instruction uses it before declaring it ; local NAMESPACE test @@ -17,7 +17,7 @@ testLabel: ENDP jp testLabel -NAMESPACE default +NAMESPACE . anotherTest: From 2579880b9d5587ebbd4ba2c31b3355f2663429d8 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 15 Oct 2017 20:55:24 +0200 Subject: [PATCH 084/247] cleanup Little optimization (tuple to set for faster search). Also remove unused REGS8 --- asmparse.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/asmparse.py b/asmparse.py index 0d645ccf0..56d2b1246 100755 --- a/asmparse.py +++ b/asmparse.py @@ -35,8 +35,7 @@ AUTORUN_ADDR = None # Where to start the execution automatically RE_DOTS = re.compile(r'\.+') -REGS16 = ('BC', 'DE', 'HL', 'SP', 'IX', 'IY') # 16 Bits registers -REGS8 = ('A', 'B', 'C', 'D', 'E', 'H', 'L', 'IXh', 'IXl', 'IYh', 'IYl') +REGS16 = {'BC', 'DE', 'HL', 'SP', 'IX', 'IY'} # 16 Bits registers precedence = ( ('left', 'RSHIFT', 'LSHIFT', 'BAND', 'BOR', 'BXOR'), From bff9474c3bf7159b16ca2caef6564a887934db43 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 18 Oct 2017 22:59:06 +0200 Subject: [PATCH 085/247] add headerless mode With the command line flag --headerless the compiler does not generate neither ASM prologue nor epilogue. --- arch/zx48k/backend/__init__.py | 9 ++++++++- tests/functional/headerless.asm | 17 +++++++++++++++++ tests/functional/headerless.bas | 6 ++++++ zxb.py | 3 +++ 4 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 tests/functional/headerless.asm create mode 100644 tests/functional/headerless.bas diff --git a/arch/zx48k/backend/__init__.py b/arch/zx48k/backend/__init__.py index 8dba89589..9dd89269c 100644 --- a/arch/zx48k/backend/__init__.py +++ b/arch/zx48k/backend/__init__.py @@ -201,6 +201,8 @@ def init(): OPTIONS.add_option('heap_start_label', str, 'ZXBASIC_MEM_HEAP') # Labels for HEAP SIZE (might not be used if not needed) OPTIONS.add_option('heap_size_label', str, 'ZXBASIC_HEAP_SIZE') + # Flag for headerless mode (No prologue / epilogue) + OPTIONS.add_option('headerless', bool, False) def new_ASMID(): @@ -402,6 +404,9 @@ def _end(ins): FLAG_end_emitted = True output.append('%s:' % END_LABEL) + if OPTIONS.headerless.value: + return output + ['ret'] + output.append('di') output.append('ld hl, (%s)' % CALL_BACK) output.append('ld sp, hl') @@ -2164,7 +2169,9 @@ def __str__(self): # Program Start routine # ------------------------- def emit_start(): - output = [] + output = list() + if OPTIONS.headerless.value: + return output output.append('org %s' % OPTIONS.org.value) diff --git a/tests/functional/headerless.asm b/tests/functional/headerless.asm new file mode 100644 index 000000000..b49ecb8b4 --- /dev/null +++ b/tests/functional/headerless.asm @@ -0,0 +1,17 @@ + ld a, (_a) + inc a + ld (_a), a + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + ret + +ZXBASIC_USER_DATA: +_a: + DEFB 02h + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/headerless.bas b/tests/functional/headerless.bas new file mode 100644 index 000000000..06fe0c957 --- /dev/null +++ b/tests/functional/headerless.bas @@ -0,0 +1,6 @@ +REM a headerless (no prologuqe in ASM) program +#pragma headerless=true + +DIM a as UByte = 2 +LET a = a + 1 + diff --git a/zxb.py b/zxb.py index 61bbb2de1..a49e97eff 100755 --- a/zxb.py +++ b/zxb.py @@ -141,6 +141,8 @@ def main(args=None): help='Add colon separated list of directories to add to include path. e.g. -I dir1:dir2') parser.add_argument('--strict', action='store_true', help='Enables strict mode. Force explicit type declaration') + parser.add_argument('--headerless', action='store_true', + help='Header-less mode: omit asm prologue and epilogue') parser.add_argument('--version', action='version', version='%(prog)s {0}'.format(VERSION)) options = parser.parse_args(args=args) @@ -166,6 +168,7 @@ def main(args=None): OPTIONS.explicit.value = options.explicit OPTIONS.memory_map.value = options.memory_map OPTIONS.strict.value = options.strict + OPTIONS.headerless.value = options.headerless if options.defines: for i in options.defines: From 72a407b7d28c252b95e10a5749d7edcefbb6c56a Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 20 Oct 2017 00:33:30 +0200 Subject: [PATCH 086/247] reset global counters on main() This must be done every time the main() function is called. --- tests/functional/test.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/functional/test.py b/tests/functional/test.py index f0f7a8cc1..d51470a88 100755 --- a/tests/functional/test.py +++ b/tests/functional/test.py @@ -466,6 +466,11 @@ def main(argv=None): global STDERR global INLINE global CLOSE_STDERR + global COUNTER + global FAILED + global EXIT_CODE + + COUNTER = FAILED = EXIT_CODE = 0 parser = argparse.ArgumentParser(description='Test compiler output against source code samples') parser.add_argument('-d', '--show-diff', action='store_true', help='Shows output difference on failure') From 5ec96199a08da29a1d9bf57e3c6f6d5f76722066 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 20 Oct 2017 00:35:01 +0200 Subject: [PATCH 087/247] allow ANY type in global options The global OPTIONS container now allows any type (None was not always possible) using the options.ANYTYPE value as type_ parameter. --- api/config.py | 7 ++++--- api/options.py | 11 ++++++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/api/config.py b/api/config.py index c99aec091..9868e8d29 100644 --- a/api/config.py +++ b/api/config.py @@ -14,6 +14,7 @@ # The options container from . import options from . import global_ +from .options import ANYTYPE # ------------------------------------------------------ # Common setup and configuration for all tools @@ -30,9 +31,9 @@ def init(): OPTIONS.add_option('Debug', int, 0) # Default console redirections - OPTIONS.add_option('stdin', None, sys.stdin) - OPTIONS.add_option('stdout', None, sys.stdout) - OPTIONS.add_option('stderr', None, sys.stderr) + OPTIONS.add_option('stdin', ANYTYPE, sys.stdin) + OPTIONS.add_option('stdout', ANYTYPE, sys.stdout) + OPTIONS.add_option('stderr', ANYTYPE, sys.stderr) # ---------------------------------------------------------------------- # Default Options and Compilation Flags diff --git a/api/options.py b/api/options.py index cbb5860f4..541852699 100644 --- a/api/options.py +++ b/api/options.py @@ -15,7 +15,14 @@ FALSE = false = False -__all__ = ['Option', 'Options'] +__all__ = ['Option', 'Options', 'ANYTYPE'] + + +class ANYTYPE(object): + """ Dummy class to signal any value + """ + pass + # ---------------------------------------------------------------------- # Exception for duplicated Options @@ -127,6 +134,8 @@ def add_option(self, name, type_=None, default_value=None): if type_ is None and default_value is not None: type_ = type(default_value) + elif type_ is ANYTYPE: + type_ = None self.options[name] = Option(name, type_, default_value) setattr(self, name, self.options[name]) From 924334f407131f0291bae5465cc4def75fcd3bc3 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 20 Oct 2017 00:36:05 +0200 Subject: [PATCH 088/247] add test_XXX to test basic programs This adds test_basic, test_asm and test_prepro, which are run by py.test (and tox), meaning every test is now atomic and allows coverage analysis. --- tests/functional/test.py | 20 ++++++++++---------- tests/functional/test_.py | 22 ++++++++++++++-------- tests/functional/test_asm.py | 22 ++++++++++++++++++++++ tests/functional/test_basic.py | 21 +++++++++++++++++++++ tests/functional/test_prepro.py | 21 +++++++++++++++++++++ tox.ini | 1 - 6 files changed, 88 insertions(+), 19 deletions(-) create mode 100755 tests/functional/test_asm.py create mode 100755 tests/functional/test_basic.py create mode 100755 tests/functional/test_prepro.py diff --git a/tests/functional/test.py b/tests/functional/test.py index d51470a88..4b6de32ed 100755 --- a/tests/functional/test.py +++ b/tests/functional/test.py @@ -12,7 +12,7 @@ reOPT = re.compile(r'^opt([0-9]+)_') # To detect -On tests -reBIN = re.compile(r'^(tzx|tap)_') # To detect tzx / tap test +reBIN = re.compile(r'^(?:.*/)?(tzx|tap)_.*') # To detect tzx / tap test EXIT_CODE = 0 FILTER = r'^(([ \t]*;)|(#[ \t]*line))' @@ -210,16 +210,15 @@ def _get_testbas_options(fname): if not UPDATE: tfname = os.path.join(TEMP_DIR, getName(fname) + os.extsep + ext) else: - tfname = getName(fname) + os.extsep + ext + tfname = os.path.join(os.path.dirname(fname), getName(fname) + os.extsep + ext) options.extend(['--%s' % ext, fname, '-o', tfname, '-a', '-B'] + prep) else: ext = 'asm' if not UPDATE: - tfname = os.path.join(TEMP_DIR, 'test' + fname + os.extsep + ext) + tfname = os.path.join(TEMP_DIR, 'test' + getName(fname) + os.extsep + ext) else: - tfname = getName(fname) + os.extsep + ext + tfname = os.path.join(os.path.dirname(fname), getName(fname) + os.extsep + ext) options.extend(['--asm', fname, '-o', tfname] + prep) - return options, tfname, ext @@ -267,9 +266,9 @@ def testASM(fname, inline=None): if inline is None: inline = INLINE - tfname = os.path.join(TEMP_DIR, 'test' + fname + os.extsep + 'bin') + tfname = os.path.join(TEMP_DIR, 'test' + getName(fname) + os.extsep + 'bin') prep = ['-e', '/dev/null'] if CLOSE_STDERR else ['-e', STDERR] - okfile = getName(fname) + os.extsep + 'bin' + okfile = os.path.join(os.path.dirname(fname), getName(fname) + os.extsep + 'bin') if UPDATE: tfname = okfile @@ -306,7 +305,7 @@ def testBAS(fname, filter_=None, inline=None): inline = INLINE options, tfname, ext = _get_testbas_options(fname) - okfile = getName(fname) + os.extsep + ext + okfile = os.path.join(os.path.dirname(fname), getName(fname) + os.extsep + ext) if UPDATE and os.path.exists(okfile): os.unlink(okfile) @@ -335,9 +334,10 @@ def testFiles(file_list): COUNTER = 0 for fname in file_list: + fname = fname ext = getExtension(fname) if ext == 'asm': - if os.path.exists(getName(fname) + os.extsep + 'bas'): + if os.path.exists(os.path.join(os.path.dirname(fname), getName(fname) + os.extsep + 'bas')): continue # Ignore asm files which have a .bas since they're test results result = testASM(fname, inline=INLINE) elif ext == 'bas': @@ -348,7 +348,7 @@ def testFiles(file_list): result = None COUNTER += 1 - _msg(("%4i " % COUNTER) + fname + ':') + _msg(("%4i " % COUNTER) + getName(fname) + ':') if result: _msg('ok \r') diff --git a/tests/functional/test_.py b/tests/functional/test_.py index d28595a8c..12e491208 100755 --- a/tests/functional/test_.py +++ b/tests/functional/test_.py @@ -107,10 +107,6 @@ """ -def process_file(fname): - test.main(['-S', '-q', fname]) - - class OutputProxy(six.StringIO): """A simple interface to replace sys.stdout so doctest can capture it. @@ -122,15 +118,25 @@ def flush(self): sys.stdout.flush() -def main(): +def process_file(fname): try: test.set_temp_dir() test.FOUT = OutputProxy() - result = doctest.testmod() # evals to True on failure - print(result) - return int(result.failed) + current_path = os.path.abspath(os.getcwd()) + if os.path.dirname(fname): + os.chdir(os.path.abspath(os.path.dirname(fname))) + fname = os.path.basename(fname) + + test.main(['-S', '-q', fname]) + os.chdir(current_path) finally: os.rmdir(test.TEMP_DIR) + test.TEMP_DIR = None + + +def main(): + result = doctest.testmod() # evaluates to True on failure + return int(result.failed) if __name__ == '__main__': diff --git a/tests/functional/test_asm.py b/tests/functional/test_asm.py new file mode 100755 index 000000000..e0220ba55 --- /dev/null +++ b/tests/functional/test_asm.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import test +import os +import sys +import pytest + + +TEST_PATH = os.path.dirname(os.path.realpath(__file__)) + + +@pytest.mark.parametrize('fname', [os.path.join(TEST_PATH, f) for f in os.listdir(TEST_PATH) if f.endswith(".asm")]) +def test_asm(fname): + test.main(['-d', '-e', '/dev/null', fname]) + if test.COUNTER == 0: + return + + sys.stderr.write("Total: %i, Failed: %i (%3.2f%%)\n" % + (test.COUNTER, test.FAILED, 100.0 * test.FAILED / float(test.COUNTER))) + + assert test.EXIT_CODE == 0, "BASIC program test failed" diff --git a/tests/functional/test_basic.py b/tests/functional/test_basic.py new file mode 100755 index 000000000..c387230c6 --- /dev/null +++ b/tests/functional/test_basic.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import test +import os +import sys +import pytest + + +TEST_PATH = os.path.dirname(os.path.realpath(__file__)) + + +@pytest.mark.parametrize('fname', [os.path.join(TEST_PATH, f) for f in os.listdir(TEST_PATH) if f.endswith(".bas")]) +def test_basic(fname): + test.main(['-d', '-e', '/dev/null', fname]) + if test.COUNTER == 0: + return + sys.stderr.write("Total: %i, Failed: %i (%3.2f%%)\n" % + (test.COUNTER, test.FAILED, 100.0 * test.FAILED / float(test.COUNTER))) + + assert test.EXIT_CODE == 0, "BASIC program test failed" diff --git a/tests/functional/test_prepro.py b/tests/functional/test_prepro.py new file mode 100755 index 000000000..b16807649 --- /dev/null +++ b/tests/functional/test_prepro.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import test +import os +import sys +import pytest + + +TEST_PATH = os.path.dirname(os.path.realpath(__file__)) + + +@pytest.mark.parametrize('fname', [os.path.join(TEST_PATH, f) for f in os.listdir(TEST_PATH) if f.endswith(".bi")]) +def test_prepro(fname): + test.main(['-d', '-e', '/dev/null', fname]) + if test.COUNTER == 0: + return + sys.stderr.write("Total: %i, Failed: %i (%3.2f%%)\n" % + (test.COUNTER, test.FAILED, 100.0 * test.FAILED / float(test.COUNTER))) + + assert test.EXIT_CODE == 0, "BASIC program test failed" diff --git a/tox.ini b/tox.ini index 6ecda7347..1ec7a5446 100644 --- a/tox.ini +++ b/tox.ini @@ -8,7 +8,6 @@ deps = -rrequirements.txt commands = py.test - /bin/bash -c 'cd ./tests/functional && make' [flake8] max-line-length = 120 From 4c2ca367d26f9ddb42a17339d4780b63f8e5db76 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 24 Oct 2017 23:47:05 +0200 Subject: [PATCH 089/247] update symbols test --- tests/symbols/test_symbolARRAYACCESS.py | 2 ++ tests/symbols/test_symbolBINARY.py | 2 ++ tests/symbols/test_symbolBOUND.py | 4 ++++ tests/symbols/test_symbolTYPECAST.py | 11 +++++++---- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/tests/symbols/test_symbolARRAYACCESS.py b/tests/symbols/test_symbolARRAYACCESS.py index bd0759086..40b187f79 100644 --- a/tests/symbols/test_symbolARRAYACCESS.py +++ b/tests/symbols/test_symbolARRAYACCESS.py @@ -10,10 +10,12 @@ import api.config as config from api.symboltable import SymbolTable from symbols.type_ import Type +import zxbpp class TestSymbolARRAYACCESS(TestCase): def setUp(self): + zxbpp.init() l1 = 1 l2 = 2 l3 = 3 diff --git a/tests/symbols/test_symbolBINARY.py b/tests/symbols/test_symbolBINARY.py index 30d956f84..11a6ed208 100644 --- a/tests/symbols/test_symbolBINARY.py +++ b/tests/symbols/test_symbolBINARY.py @@ -7,10 +7,12 @@ from api.config import OPTIONS import symbols from symbols.type_ import Type +import zxbpp class TestSymbolBINARY(TestCase): def setUp(self): + zxbpp.init() self.l = symbols.VAR('a', lineno=1, type_=Type.ubyte) self.r = symbols.NUMBER(3, lineno=2) self.b = symbols.BINARY('PLUS', self.l, self.r, lineno=3) diff --git a/tests/symbols/test_symbolBOUND.py b/tests/symbols/test_symbolBOUND.py index 518492bcc..a9978092b 100644 --- a/tests/symbols/test_symbolBOUND.py +++ b/tests/symbols/test_symbolBOUND.py @@ -7,9 +7,13 @@ from api.config import OPTIONS import symbols +import zxbpp class TestSymbolBOUND(TestCase): + def setUp(self): + zxbpp.init() + def test__init__(self): self.assertRaises(AssertionError, symbols.BOUND, 'a', 3) self.assertRaises(AssertionError, symbols.BOUND, 1, 'a') diff --git a/tests/symbols/test_symbolTYPECAST.py b/tests/symbols/test_symbolTYPECAST.py index 1b90a92f3..b1c2ce43c 100644 --- a/tests/symbols/test_symbolTYPECAST.py +++ b/tests/symbols/test_symbolTYPECAST.py @@ -9,12 +9,15 @@ from api.config import OPTIONS from six import StringIO from api.constants import CLASS +import zxbpp + __autor__ = 'boriel' class TestSymbolTYPECAST(TestCase): def setUp(self): + zxbpp.init() self.t = TYPECAST(Type.float_, NUMBER(3, lineno=1), lineno=2) if OPTIONS.has_option('stderr'): @@ -44,8 +47,8 @@ def test_make_node(self): self.assertEqual(t, self.t.operand) def test_make_const(self): - ''' Must return a number - ''' + """ Must return a number + """ v = VAR('a', lineno=1, type_=Type.byte_) v.default_value = 3 v.class_ = CLASS.const @@ -54,8 +57,8 @@ def test_make_const(self): self.assertEqual(t, 3) def test_make_node_None(self): - ''' None is allowed as operand - ''' + """ None is allowed as operand + """ self.assertIsNone(TYPECAST.make_node(Type.float_, None, lineno=2)) def test_make_node_fail_type(self): From 9bac300b8f3c18f0da9b4c92cdc40838b38c5f3f Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 24 Oct 2017 23:50:48 +0200 Subject: [PATCH 090/247] bugfix: initialize the api.config api.config.init() was not being called when zxbasm was being invoked from the command line or with its main() function. Fixed. --- zxbasm.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zxbasm.py b/zxbasm.py index 319b6539e..38f0b3d0e 100755 --- a/zxbasm.py +++ b/zxbasm.py @@ -19,6 +19,7 @@ from asmparse import Asm, Expr, Container import zxbpp +import api.config from api.config import OPTIONS from api import global_ @@ -28,6 +29,7 @@ def main(args=None): # Initializes asm parser state + api.config.init() asmparse.init() zxbpp.init() From 71c1a62874df81ba6b255c120aa275bb69391386 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 25 Oct 2017 13:15:36 +0200 Subject: [PATCH 091/247] moved doctstring text to a file This allows py.test to detect it. --- tests/functional/test_.py | 109 ++----------------------------- tests/functional/test_errmsg.txt | 96 +++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 102 deletions(-) create mode 100644 tests/functional/test_errmsg.txt diff --git a/tests/functional/test_.py b/tests/functional/test_.py index 12e491208..c3edb13ac 100755 --- a/tests/functional/test_.py +++ b/tests/functional/test_.py @@ -8,105 +8,6 @@ import test -__doc__ = """ ->>> process_file('doloop1.bas') -doloop1.bas:2: warning: Infinite empty loop ->>> process_file('dountil1.bas') -dountil1.bas:2: warning: Condition is always False -dountil1.bas:2: warning: Empty loop ->>> process_file('doloop2.bas') -doloop2.bas:4: warning: Using default implicit type 'ubyte' for 'a' -doloop2.bas:5: warning: Condition is always True -doloop2.bas:8: warning: Condition is always True -doloop2.bas:12: warning: Condition is always False -doloop2.bas:4: warning: Variable 'a' is never used ->>> process_file('dowhile1.bas') -dowhile1.bas:1: warning: Condition is always True -dowhile1.bas:1: warning: Empty loop ->>> process_file('subcall1.bas') -subcall1.bas:6: 'test' is SUBROUTINE not a FUNCTION ->>> process_file('subcall2.bas') -subcall2.bas:6: 'test' is a SUBROUTINE, not a FUNCTION ->>> process_file('prepro05.bi') -prepro05.bi:3: warning: "test" redefined (previous definition at prepro05.bi:2) ->>> process_file('prepro07.bi') -prepro07.bi:2: Error: Duplicated name parameter "x" ->>> process_file('prepro28.bi') -prepro28.bi:3: Error: invalid directive #defien ->>> process_file('param3.bas') -param3.bas:3: warning: Parameter 's' is never used -param3.bas:5: Function 'test' (previously declared at 3) type mismatch -param3.bas:6: Type Error: Function must return a numeric value, not a string ->>> process_file('typecast1.bas') -typecast1.bas:5: Cannot convert value to string. Use STR() function ->>> process_file('typecast2.bas') -typecast2.bas:1: warning: Parameter 'c' is never used -typecast2.bas:10: Cannot convert string to a value. Use VAL() function ->>> process_file('jr1.asm') -jr1.asm:12: Relative jump out of range ->>> process_file('jr2.asm') -jr2.asm:2: Relative jump out of range ->>> process_file('mcleod3.bas') -mcleod3.bas:3: 'GenerateSpaces' is neither an array nor a function. -mcleod3.bas:1: warning: Parameter 'path' is never used -mcleod3.bas:6: warning: Parameter 'n' is never used ->>> process_file('poke3.bas') -poke3.bas:4: Variable 'a' is an array and cannot be used in this context ->>> process_file('poke5.bas') -poke5.bas:4: Variable 'a' is an array and cannot be used in this context ->>> process_file('arrlabels10.bas') -arrlabels10.bas:3: warning: Using default implicit type 'float' for 'a' -arrlabels10.bas:3: Can't convert non-numeric value to float at compile time -arrlabels10.bas:3: Can't convert non-numeric value to float at compile time ->>> process_file('arrlabels10c.bas') -arrlabels10c.bas:3: Can't convert non-numeric value to string at compile time -arrlabels10c.bas:3: Can't convert non-numeric value to string at compile time ->>> process_file('arrlabels10d.bas') -arrlabels10d.bas:3: Undeclared array "a" ->>> process_file('arrlabels11.bas') -arrlabels11.bas:4: Initializer expression is not constant. ->>> process_file('lexerr.bas') -lexerr.bas:1: ignoring illegal character '%' -lexerr.bas:1: warning: Using default implicit type 'float' for 'a' -lexerr.bas:1: Syntax Error. Unexpected token '%' ->>> process_file('opt2_nogoto.bas') -opt2_nogoto.bas:2: Undeclared label "nolabel" ->>> process_file('nosub.bas') -nosub.bas:3: function 'nofunc' declared but not implemented ->>> process_file('incbin0.asm') -incbin0.asm:3: Error: file 'nofile.bin' not found ->>> process_file('align3.asm') -align3.asm:2: ALIGN value must be greater than 1 ->>> process_file('rst0.asm') -rst0.asm:2: Invalid RST number 1 ->>> process_file('im0.asm') -im0.asm:2: Invalid IM number 3 ->>> process_file('orgbad.asm') -orgbad.asm:2: Memory ORG out of range [0 .. 65535]. Current value: -1 ->>> process_file('defsbad.asm') -defsbad.asm:2: too many arguments for DEFS ->>> process_file('asmprepro.asm') -asmprepro.asm:8: warning: Recursive inclusion -asmprepro.asm:12: warning: Recursive inclusion -asmprepro.asm:12: warning: Recursive inclusion ->>> process_file('strict.bas') -strict.bas:2: warning: Using default implicit type 'float' for 'b' -strict.bas:4: strict mode: missing type declaration for 'a' ->>> process_file('errletfunc.bas') -errletfunc.bas:5: Cannot assign a value to 'x'. It's not a variable ->>> process_file('read0.bas') -read0.bas:12: 'x' is SUBROUTINE not a FUNCTION ->>> process_file('read1.bas') -read1.bas:11: Variable 'x' is an array and cannot be used in this context ->>> process_file('read3.bas') -read3.bas:9: 'x' is neither an array nor a function. ->>> process_file('read6.bas') -read6.bas:12: Syntax error. Can only read a variable or an array element ->>> process_file('data0.bas') -data0.bas:2: 'b' is neither an array nor a function. -""" - - class OutputProxy(six.StringIO): """A simple interface to replace sys.stdout so doctest can capture it. @@ -120,13 +21,14 @@ def flush(self): def process_file(fname): try: + current_path = os.path.abspath(os.getcwd()) test.set_temp_dir() test.FOUT = OutputProxy() - current_path = os.path.abspath(os.getcwd()) if os.path.dirname(fname): os.chdir(os.path.abspath(os.path.dirname(fname))) fname = os.path.basename(fname) - + else: + os.chdir(os.path.realpath(os.path.dirname(__file__))) test.main(['-S', '-q', fname]) os.chdir(current_path) finally: @@ -135,7 +37,10 @@ def process_file(fname): def main(): - result = doctest.testmod() # evaluates to True on failure + current_path = os.path.abspath(os.getcwd()) + os.chdir(os.path.realpath(os.path.dirname(__file__) or os.curdir)) + result = doctest.testfile('test_errmsg.txt') # evaluates to True on failure + os.chdir(current_path) return int(result.failed) diff --git a/tests/functional/test_errmsg.txt b/tests/functional/test_errmsg.txt new file mode 100644 index 000000000..550fc72c1 --- /dev/null +++ b/tests/functional/test_errmsg.txt @@ -0,0 +1,96 @@ +>>> from test_ import process_file +>>> process_file('doloop1.bas') +doloop1.bas:2: warning: Infinite empty loop +>>> process_file('dountil1.bas') +dountil1.bas:2: warning: Condition is always False +dountil1.bas:2: warning: Empty loop +>>> process_file('doloop2.bas') +doloop2.bas:4: warning: Using default implicit type 'ubyte' for 'a' +doloop2.bas:5: warning: Condition is always True +doloop2.bas:8: warning: Condition is always True +doloop2.bas:12: warning: Condition is always False +doloop2.bas:4: warning: Variable 'a' is never used +>>> process_file('dowhile1.bas') +dowhile1.bas:1: warning: Condition is always True +dowhile1.bas:1: warning: Empty loop +>>> process_file('subcall1.bas') +subcall1.bas:6: 'test' is SUBROUTINE not a FUNCTION +>>> process_file('subcall2.bas') +subcall2.bas:6: 'test' is a SUBROUTINE, not a FUNCTION +>>> process_file('prepro05.bi') +prepro05.bi:3: warning: "test" redefined (previous definition at prepro05.bi:2) +>>> process_file('prepro07.bi') +prepro07.bi:2: Error: Duplicated name parameter "x" +>>> process_file('prepro28.bi') +prepro28.bi:3: Error: invalid directive #defien +>>> process_file('param3.bas') +param3.bas:3: warning: Parameter 's' is never used +param3.bas:5: Function 'test' (previously declared at 3) type mismatch +param3.bas:6: Type Error: Function must return a numeric value, not a string +>>> process_file('typecast1.bas') +typecast1.bas:5: Cannot convert value to string. Use STR() function +>>> process_file('typecast2.bas') +typecast2.bas:1: warning: Parameter 'c' is never used +typecast2.bas:10: Cannot convert string to a value. Use VAL() function +>>> process_file('jr1.asm') +jr1.asm:12: Relative jump out of range +>>> process_file('jr2.asm') +jr2.asm:2: Relative jump out of range +>>> process_file('mcleod3.bas') +mcleod3.bas:3: 'GenerateSpaces' is neither an array nor a function. +mcleod3.bas:1: warning: Parameter 'path' is never used +mcleod3.bas:6: warning: Parameter 'n' is never used +>>> process_file('poke3.bas') +poke3.bas:4: Variable 'a' is an array and cannot be used in this context +>>> process_file('poke5.bas') +poke5.bas:4: Variable 'a' is an array and cannot be used in this context +>>> process_file('arrlabels10.bas') +arrlabels10.bas:3: warning: Using default implicit type 'float' for 'a' +arrlabels10.bas:3: Can't convert non-numeric value to float at compile time +arrlabels10.bas:3: Can't convert non-numeric value to float at compile time +>>> process_file('arrlabels10c.bas') +arrlabels10c.bas:3: Can't convert non-numeric value to string at compile time +arrlabels10c.bas:3: Can't convert non-numeric value to string at compile time +>>> process_file('arrlabels10d.bas') +arrlabels10d.bas:3: Undeclared array "a" +>>> process_file('arrlabels11.bas') +arrlabels11.bas:4: Initializer expression is not constant. +>>> process_file('lexerr.bas') +lexerr.bas:1: ignoring illegal character '%' +lexerr.bas:1: warning: Using default implicit type 'float' for 'a' +lexerr.bas:1: Syntax Error. Unexpected token '%' +>>> process_file('opt2_nogoto.bas') +opt2_nogoto.bas:2: Undeclared label "nolabel" +>>> process_file('nosub.bas') +nosub.bas:3: function 'nofunc' declared but not implemented +>>> process_file('incbin0.asm') +incbin0.asm:3: Error: file 'nofile.bin' not found +>>> process_file('align3.asm') +align3.asm:2: ALIGN value must be greater than 1 +>>> process_file('rst0.asm') +rst0.asm:2: Invalid RST number 1 +>>> process_file('im0.asm') +im0.asm:2: Invalid IM number 3 +>>> process_file('orgbad.asm') +orgbad.asm:2: Memory ORG out of range [0 .. 65535]. Current value: -1 +>>> process_file('defsbad.asm') +defsbad.asm:2: too many arguments for DEFS +>>> process_file('asmprepro.asm') +asmprepro.asm:8: warning: Recursive inclusion +asmprepro.asm:12: warning: Recursive inclusion +asmprepro.asm:12: warning: Recursive inclusion +>>> process_file('strict.bas') +strict.bas:2: warning: Using default implicit type 'float' for 'b' +strict.bas:4: strict mode: missing type declaration for 'a' +>>> process_file('errletfunc.bas') +errletfunc.bas:5: Cannot assign a value to 'x'. It's not a variable +>>> process_file('read0.bas') +read0.bas:12: 'x' is SUBROUTINE not a FUNCTION +>>> process_file('read1.bas') +read1.bas:11: Variable 'x' is an array and cannot be used in this context +>>> process_file('read3.bas') +read3.bas:9: 'x' is neither an array nor a function. +>>> process_file('read6.bas') +read6.bas:12: Syntax error. Can only read a variable or an array element +>>> process_file('data0.bas') +data0.bas:2: 'b' is neither an array nor a function. From cc8484a055761df8d8c3c7005b46d3d64b5fa5d8 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 25 Oct 2017 13:42:46 +0200 Subject: [PATCH 092/247] allow posargs in tox This allows to specify -- test_xxx in tox from the command line. --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 1ec7a5446..c8d61bb2e 100644 --- a/tox.ini +++ b/tox.ini @@ -7,7 +7,7 @@ deps = pytest -rrequirements.txt commands = - py.test + py.test {posargs} [flake8] max-line-length = 120 From 562c6778e9809fb69e12ba89d2bbdd3525791a3e Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 25 Oct 2017 16:16:32 +0200 Subject: [PATCH 093/247] avoid E722 and E741 flake8 errors This is a momentanous workaround to avoid E722 and E741 (which previously were only warnings). This is done because most of the backend part is gonna be refactored almost from scratch. --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index c8d61bb2e..2dd789f67 100644 --- a/tox.ini +++ b/tox.ini @@ -11,7 +11,7 @@ commands = [flake8] max-line-length = 120 -ignore = E731 +ignore = E722, E731, E741 exclude = .cache/, .tox/, From c6a6dbbd0c67ec18ebfecb80e3d590943378c45d Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 25 Oct 2017 17:28:50 +0200 Subject: [PATCH 094/247] prevents error on temp dirs When creating temporary directories, py.test might fail when scanning them as these directories are efimeral and not for testing. So they're now excluded. Also updates to python 3.6 --- tox.ini | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 2dd789f67..a5726b6f4 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py27,py35,pypy,flake8 +envlist = py27,py36,pypy,flake8 [testenv] setenv = LANG=en_US.UTF-8 @@ -29,3 +29,6 @@ commands = flake8 [travis] python = 3.5: py35, flake8 + +[pytest] +norecursedirs = test_*tmp From 1531bcec7f324affe2c80513979705f03fc8be68 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 25 Oct 2017 17:30:42 +0200 Subject: [PATCH 095/247] update travis setup to python 3.6 --- .travis.yml | 2 +- tox.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7b8fbfca9..e324d728d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: python python: # - "2.7" <- Unsupported, uses 2.7.9 ? - - "3.5" + - "3.6" # PyPy versions # - "pypy" # PyPy2 2.5.0 # - "pypy3" # Pypy3 2.4.0 diff --git a/tox.ini b/tox.ini index a5726b6f4..f976526fe 100644 --- a/tox.ini +++ b/tox.ini @@ -28,7 +28,7 @@ commands = flake8 [travis] python = - 3.5: py35, flake8 + 3.6: py36, flake8 [pytest] norecursedirs = test_*tmp From 912bcd315d80a3ddf747e680536214c60a1a0754 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 23 Oct 2017 00:13:24 +0200 Subject: [PATCH 096/247] update pong example Now it finish at 10 points --- examples/pong.bas | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/examples/pong.bas b/examples/pong.bas index ec4270e4b..b31e522a5 100644 --- a/examples/pong.bas +++ b/examples/pong.bas @@ -24,6 +24,8 @@ {{139, 135}, {131, 135}, {140, 141}} _ ' Number 9 } 20 BORDER 0: PAPER 0: INK 7: BRIGHT 1: OVER 1: CLS + PRINT AT 10, 5; BOLD 1; "PRESS Q or 4 TO MOVE UP" + PRINT AT 11, 4; BOLD 1; "PRESS A or 3 TO MOVE DOWN": PAUSE 0 DIM h, xx, yy, p, oldX, oldY As Byte DIM x, y, dx, dy as Fixed DIM px, py, NUM as Byte @@ -40,10 +42,11 @@ CONST dFast as UInteger = 400 CONST dSlow as UInteger = 1000 CONST diffRate As Float = 1.125: REM difficulty rate + CONST pointsToWin As Byte = 10: REM Points to Win DIM score(1) As Byte: REM Scores -30 LET xx = 31: FOR yy = minY TO maxY STEP 2: GOSUB 2000: NEXT yy +30 CLS: LET xx = 31: FOR yy = minY TO maxY STEP 2: GOSUB 2000: NEXT yy 40 DIM coords(1, 1) As Byte: REM Player 0 (Left) and 1 (Right) coordinates 50 LET h = 5: REM players height (in "points"). A "point" is 4 pixels 60 LET x = startX: LET y = startY: REM Screen resolution is 64 @@ -121,10 +124,10 @@ 200 REM Checks if Player moves ("4", "3") 210 LET px = coords(user, 0): LET py = coords(user, 1) -220 if py > minY AND INKEY$ = "4" THEN: REM Must go up +220 if py > minY AND (INKEY$ = "4" OR INKEY$ = "q") THEN: REM Must go up LET p = user GOSUB 1500: REM Updates player padel (up) - ELSEIF py + h < maxY AND INKEY$ = "3" THEN + ELSEIF py + h < maxY AND (INKEY$ = "3" OR INKEY$ = "a") THEN: REM Must go down LET p = user GOSUB 1600: REM Updates player padel (down) END IF @@ -196,7 +199,8 @@ 3050 LET NUM = sc Mod 10 3060 GOSUB 5000 3070 NEXT player -3080 RETURN +3080 GOSUB 6000 +3090 RETURN 5000 REM Prints Number NUM at atY, atX 5010 FOR ny = 0 TO 2: FOR nx = 0 TO 1 @@ -204,3 +208,23 @@ 5030 NEXT nx: NEXT ny 5040 RETURN +6000 REM Check scores +6010 FOR player = 0 TO 1 +6020 IF score(player) >= pointsToWin THEN + CLS + PRINT AT 10, 10; + IF player = comp THEN + PRINT BOLD 1; "I WIN!" + ELSE + PRINT BOLD 1; "YOU WIN!" + END IF + DO LOOP WHILE INKEY$ <> "" + PAUSE 500 + PRINT AT 21, 3; BOLD 1; "PRESS ANY KEY TO CONTINUE"; + PAUSE 0 + GOTO 30 + END IF +6030 NEXT player +6040 RETURN + + From 6339f1a5b94e291db493363d1b988e4ea3e7a4bb Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 27 Oct 2017 11:59:31 +0200 Subject: [PATCH 097/247] bugfix: fix read / write errors Using POKE before an ASM region in a fastcall function might overwrite the registers used as parameters. Fixed. Thanks to @emook (D. Saphier) for the report. ;) --- library/esxdos.bas | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/esxdos.bas b/library/esxdos.bas index ac792a751..609d0c393 100644 --- a/library/esxdos.bas +++ b/library/esxdos.bas @@ -135,6 +135,8 @@ Function FASTCALL ESXDosWrite(ByVal handle as Byte, _ Asm ;FASTCALL implies handle is already in A register + ld hl, EDOS_ERR_NR + ld (hl), 255 ; sets 255 = OK pop de ; ret address pop hl ; buffer address pop bc ; bc <- nbytes @@ -169,10 +171,10 @@ End Function Function FASTCALL ESXDosRead(ByVal handle as Byte, _ ByVal buffer as UInteger, _ ByVal nbytes as UInteger) as Uinteger - poke EDOS_ERR_NR,255 - Asm ;FASTCALL implies handle is already in A register + ld hl, EDOS_ERR_NR + ld (hl), 255 ; sets 255 = OK pop de ; ret address pop hl ; buffer address pop bc ; bc <- nbytes From 4168200d3a3ea5aca330d72ede13b005f460ffd4 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 28 Oct 2017 10:20:59 +0200 Subject: [PATCH 098/247] bugfix: fix memcopy library function MemCopy library function was not correctly working. Fixed. Also added MemMove() which allows overlapping blocks. Thanks to @emook (D. Saphier) --- library-asm/memcopy.asm | 9 +- library/memcopy.bas | 56 +- tests/functional/memcpytest.asm | 1663 +++++++++++++++++++++++++++++++ tests/functional/memcpytest.bas | 13 + 4 files changed, 1722 insertions(+), 19 deletions(-) create mode 100644 tests/functional/memcpytest.asm create mode 100644 tests/functional/memcpytest.bas diff --git a/library-asm/memcopy.asm b/library-asm/memcopy.asm index 19429ebf5..d098cddc4 100644 --- a/library-asm/memcopy.asm +++ b/library-asm/memcopy.asm @@ -8,7 +8,7 @@ ; ---------------------------------------------------------------- ; Emulates both memmove and memcpy C routines -; Blocks will safely copies if they overlap +; Block will be safely copied if they overlap ; HL => Start of source block ; DE => Start of destiny block @@ -19,15 +19,16 @@ __MEMCPY: PROC LOCAL __MEMCPY2 - add hl, bc + push hl + add hl, bc ; addr of last source block byte + 1 or a sbc hl, de ; checks if DE > HL + BC - add hl, de ; recovers HL. If Carry set => DE > HL + pop hl ; recovers HL. If carry => DE > HL + BC (no overlap) jr c, __MEMCPY2 ; Now checks if DE <= HL - sbc hl, de + sbc hl, de ; Even if overlap, if DE < HL then we can LDIR safely add hl, de jr nc, __MEMCPY2 diff --git a/library/memcopy.bas b/library/memcopy.bas index 8abbf393e..4569c7e69 100644 --- a/library/memcopy.bas +++ b/library/memcopy.bas @@ -3,8 +3,6 @@ ' ' Copyleft (k) 2008 ' by Jose Rodriguez-Rosa (a.k.a. Boriel) -' -' Use this file as a template to develop your own library file ' ---------------------------------------------------------------- #ifndef __LIBRARY_MEMCOPY__ @@ -13,20 +11,21 @@ REM Avoid recursive / multiple inclusion #define __LIBRARY_MEMCOPY__ -#define memmove memcopy - +#pragma push(case_insensitive) +#pragma case_insensitive = True ' ---------------------------------------------------------------- -' sub MEMCOPY(sourceaddr, destaddr, blocklength) +' Sub MemMove(sourceaddr, destaddr, blocklength) ' ' Parameters: ' souceaddr: memory address of source block to copy ' destaddr: memory address of destiny block to copy ' length: number of bytes to copy ' -' Copies block of memory from source to dest. Block may overlap +' Copies block of memory safely from source to dest. +' Source and destiny blocks may overlap ' ---------------------------------------------------------------- -sub fastcall memcopy(source as uinteger, dest as uinteger, length as uinteger) +sub fastcall MemMove(source as uinteger, dest as uinteger, length as uinteger) asm ; Emulates both memmove and memcpy C routines ; Blocks will safely copies if they overlap @@ -35,22 +34,49 @@ sub fastcall memcopy(source as uinteger, dest as uinteger, length as uinteger) ; DE => Start of destiny block ; BC => Block length - exx - pop hl ; ret addr - exx - + pop af ; ret addr pop de ; dest pop bc ; length - - exx - push hl ; stores ret addr back - exx + push af ; stores ret addr back jp __MEMCPY end asm end sub + +' ---------------------------------------------------------------- +' Sub MemCopy(sourceaddr, destaddr, blocklength) +' +' Parameters: +' souceaddr: memory address of source block to copy +' destaddr: memory address of destiny block to copy +' length: number of bytes to copy +' +' Copies block of memory from source to dest. +' Source and destiny blocks should not overlap. +' This sub is slighly faster than memmove +' ---------------------------------------------------------------- +sub fastcall MemCopy(source as uinteger, dest as uinteger, length as uinteger) + asm +; Emulates both memmove and memcpy C routines +; Blocks will safely copies if they DON'T overlap + +; HL => Start of source block +; DE => Start of destiny block +; BC => Block length + + pop af ; ret addr + pop de ; dest + pop bc ; length + push af ; stores ret addr back + ldir + end asm +end sub + + #require "memcopy.asm" +#pragma pop(case_insensitive) + #endif diff --git a/tests/functional/memcpytest.asm b/tests/functional/memcpytest.asm new file mode 100644 index 000000000..1007f2b78 --- /dev/null +++ b/tests/functional/memcpytest.asm @@ -0,0 +1,1663 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + call __PRINT_INIT + call CLS + ld a, 1 + ld (_i), a + jp __LABEL0 +__LABEL3: + ld hl, __LABEL5 + xor a + call __PRINTSTR +__LABEL4: + ld a, (_i) + inc a + ld (_i), a +__LABEL0: + ld a, 10 + ld hl, (_i - 1) + cp h + jp nc, __LABEL3 +__LABEL2: + ld hl, 6912 + push hl + ld hl, 40000 + push hl + ld hl, 16384 + call _MemCopy + call CLS + ld hl, 0 + call __PAUSE + ld hl, 6912 + push hl + ld hl, 16384 + push hl + ld hl, 40000 + call _MemCopy + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +_MemMove: +#line 28 + pop af + pop de + pop bc + push af + jp __MEMCPY +#line 33 +_MemMove__leave: + ret +_MemCopy: +#line 59 + pop af + pop de + pop bc + push af + ldir +#line 64 +_MemCopy__leave: + ret +__LABEL5: + DEFW 0005h + DEFB 54h + DEFB 45h + DEFB 53h + DEFB 54h + DEFB 20h +#line 1 "cls.asm" + + ; JUMPS directly to spectrum CLS + ; This routine does not clear lower screen + + ;CLS EQU 0DAFh + + ; Our faster implementation + +#line 1 "sposn.asm" + + ; Printing positioning library. + PROC + LOCAL ECHO_E + +__LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. + ld de, (S_POSN) + ld hl, (MAXX) + or a + sbc hl, de + ex de, hl + ret + + +__SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. + ld hl, (MAXX) + or a + sbc hl, de + ld (S_POSN), hl ; saves it again + ret + + + ECHO_E EQU 23682 + MAXX EQU ECHO_E ; Max X position + 1 + MAXY EQU MAXX + 1 ; Max Y position + 1 + + S_POSN EQU 23688 + POSX EQU S_POSN ; Current POS X + POSY EQU S_POSN + 1 ; Current POS Y + + ENDP + +#line 9 "cls.asm" + +CLS: + PROC + + LOCAL COORDS + LOCAL __CLS_SCR + LOCAL ATTR_P + LOCAL SCREEN + + ld hl, 0 + ld (COORDS), hl + ld hl, 1821h + ld (S_POSN), hl +__CLS_SCR: + ld hl, SCREEN + ld (hl), 0 + ld d, h + ld e, l + inc de + ld bc, 6144 + ldir + + ; Now clear attributes + + ld a, (ATTR_P) + ld (hl), a + ld bc, 767 + ldir + ret + + COORDS EQU 23677 + SCREEN EQU 16384 ; Default start of the screen (can be changed) + ATTR_P EQU 23693 + ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address + + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines + ; to get the start of the screen + ENDP + +#line 78 "memcpytest.bas" +#line 1 "memcopy.asm" + + ; ---------------------------------------------------------------- + ; This file is released under the MIT License + ; + ; Copyleft (k) 2008 +; by Jose Rodriguez-Rosa (a.k.a. Boriel) + ; + ; Use this file as a template to develop your own library file + ; ---------------------------------------------------------------- + + ; Emulates both memmove and memcpy C routines + ; Block will be safely copied if they overlap + + ; HL => Start of source block + ; DE => Start of destiny block + ; BC => Block length + +__MEMCPY: + + PROC + LOCAL __MEMCPY2 + + push hl + add hl, bc ; addr of last source block byte + 1 + or a + sbc hl, de ; checks if DE > HL + BC + pop hl ; recovers HL. If carry => DE > HL + BC (no overlap) + jr c, __MEMCPY2 + + ; Now checks if DE <= HL + + sbc hl, de ; Even if overlap, if DE < HL then we can LDIR safely + add hl, de + jr nc, __MEMCPY2 + + dec bc + add hl, bc + ex de, hl + add hl, bc + ex de, hl + inc bc ; HL and DE point to the last byte position + + lddr ; Copies from end to beginning + ret + +__MEMCPY2: + ldir + ret + + ENDP +#line 79 "memcpytest.bas" +#line 1 "pause.asm" + + ; The PAUSE statement (Calling the ROM) + +__PAUSE: + ld b, h + ld c, l + jp 1F3Dh ; PAUSE_1 +#line 80 "memcpytest.bas" +#line 1 "printstr.asm" + +#line 1 "print.asm" + +; vim:ts=4:sw=4:et: + ; PRINT command routine + ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that + + + +#line 1 "in_screen.asm" + + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 3 "in_screen.asm" + +__IN_SCREEN: + ; Returns NO carry if current coords (D, E) + ; are OUT of the screen limits (MAXX, MAXY) + + PROC + LOCAL __IN_SCREEN_ERR + + ld hl, MAXX + ld a, e + cp (hl) + jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + + ld a, d + inc hl + cp (hl) + ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + ;; ret + ret c ; Return if carry (OK) + +__IN_SCREEN_ERR: +__OUT_OF_SCREEN_ERR: + ; Jumps here if out of screen + ld a, ERROR_OutOfScreen + jp __STOP ; Saves error code and exits + + ENDP +#line 8 "print.asm" +#line 1 "table_jump.asm" + + +JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A + add a, a + +JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE + ld e, a + ld d, 0 + +JUMP_HL_PLUS_DE: ; Does JP (HL + DE) + add hl, de + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl +CALL_HL: + jp (hl) + +#line 9 "print.asm" +#line 1 "ink.asm" + + ; Sets ink color in ATTR_P permanently +; Parameter: Paper color in A register + +#line 1 "const.asm" + + ; Global constants + + P_FLAG EQU 23697 + FLAGS2 EQU 23681 + ATTR_P EQU 23693 ; permanet ATTRIBUTES + ATTR_T EQU 23695 ; temporary ATTRIBUTES + CHARS EQU 23606 ; Pointer to ROM/RAM Charset + UDG EQU 23675 ; Pointer to UDG Charset + MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars + +#line 5 "ink.asm" + +INK: + PROC + LOCAL __SET_INK + LOCAL __SET_INK2 + + ld de, ATTR_P + +__SET_INK: + cp 8 + jr nz, __SET_INK2 + + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + or 7 ; Set bits 0,1,2 to enable transparency + ld (de), a + ret + +__SET_INK2: + ; Another entry. This will set the ink color at location pointer by DE + and 7 ; # Gets color mod 8 + ld b, a ; Saves the color + ld a, (de) + and 0F8h ; Clears previous value + or b + ld (de), a + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + and 0F8h ; Reset bits 0,1,2 sign to disable transparency + ld (de), a ; Store new attr + ret + + ; Sets the INK color passed in A register in the ATTR_T variable +INK_TMP: + ld de, ATTR_T + jp __SET_INK + + ENDP + +#line 10 "print.asm" +#line 1 "paper.asm" + + ; Sets paper color in ATTR_P permanently +; Parameter: Paper color in A register + + + +PAPER: + PROC + LOCAL __SET_PAPER + LOCAL __SET_PAPER2 + + ld de, ATTR_P + +__SET_PAPER: + cp 8 + jr nz, __SET_PAPER2 + inc de + ld a, (de) + or 038h + ld (de), a + ret + + ; Another entry. This will set the paper color at location pointer by DE +__SET_PAPER2: + and 7 ; # Remove + rlca + rlca + rlca ; a *= 8 + + ld b, a ; Saves the color + ld a, (de) + and 0C7h ; Clears previous value + or b + ld (de), a + inc de ; Points to MASK_T or MASK_P accordingly + ld a, (de) + and 0C7h ; Resets bits 3,4,5 + ld (de), a + ret + + + ; Sets the PAPER color passed in A register in the ATTR_T variable +PAPER_TMP: + ld de, ATTR_T + jp __SET_PAPER + ENDP + +#line 11 "print.asm" +#line 1 "flash.asm" + + ; Sets flash flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +FLASH: + ld de, ATTR_P +__SET_FLASH: + ; Another entry. This will set the flash flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + ld b, a ; Saves the color + ld a, (de) + and 07Fh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the FLASH flag passed in A register in the ATTR_T variable +FLASH_TMP: + ld de, ATTR_T + jr __SET_FLASH + +#line 12 "print.asm" +#line 1 "bright.asm" + + ; Sets bright flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +BRIGHT: + ld de, ATTR_P + +__SET_BRIGHT: + ; Another entry. This will set the bright flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + rrca + ld b, a ; Saves the color + ld a, (de) + and 0BFh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable +BRIGHT_TMP: + ld de, ATTR_T + jr __SET_BRIGHT + +#line 13 "print.asm" +#line 1 "over.asm" + + ; Sets OVER flag in P_FLAG permanently +; Parameter: OVER flag in bit 0 of A register +#line 1 "copy_attr.asm" + + + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" + + + +COPY_ATTR: + ; Just copies current permanent attribs to temporal attribs + ; and sets print mode + PROC + + LOCAL INVERSE1 + LOCAL __REFRESH_TMP + + INVERSE1 EQU 02Fh + + ld hl, (ATTR_P) + ld (ATTR_T), hl + + ld hl, FLAGS2 + call __REFRESH_TMP + + ld hl, P_FLAG + call __REFRESH_TMP + + +__SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) + + + LOCAL TABLE + LOCAL CONT2 + + rra ; Over bit to carry + ld a, (FLAGS2) + rla ; Over bit in bit 1, Over2 bit in bit 2 + and 3 ; Only bit 0 and 1 (OVER flag) + + ld c, a + ld b, 0 + + ld hl, TABLE + add hl, bc + ld a, (hl) + ld (PRINT_MODE), a + + ld hl, (P_FLAG) + xor a ; NOP -> INVERSE0 + bit 2, l + jr z, CONT2 + ld a, INVERSE1 ; CPL -> INVERSE1 + +CONT2: + ld (INVERSE_MODE), a + ret + +TABLE: + nop ; NORMAL MODE + xor (hl) ; OVER 1 MODE + and (hl) ; OVER 2 MODE + or (hl) ; OVER 3 MODE + +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" + +__REFRESH_TMP: + ld a, (hl) + and 10101010b + ld c, a + rra + or c + ld (hl), a + ret + + ENDP + +#line 4 "over.asm" + + +OVER: + PROC + + ld c, a ; saves it for later + and 2 + ld hl, FLAGS2 + res 1, (HL) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 ; # Convert to 0/1 + add a, a; # Shift left 1 bit for permanent + + ld hl, P_FLAG + res 1, (hl) + or (hl) + ld (hl), a + ret + + ; Sets OVER flag in P_FLAG temporarily +OVER_TMP: + ld c, a ; saves it for later + and 2 ; gets bit 1; clears carry + rra + ld hl, FLAGS2 + res 0, (hl) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 + ld hl, P_FLAG + res 0, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 14 "print.asm" +#line 1 "inverse.asm" + + ; Sets INVERSE flag in P_FLAG permanently +; Parameter: INVERSE flag in bit 0 of A register + + + +INVERSE: + PROC + + and 1 ; # Convert to 0/1 + add a, a; # Shift left 3 bits for permanent + add a, a + add a, a + ld hl, P_FLAG + res 3, (hl) + or (hl) + ld (hl), a + ret + + ; Sets INVERSE flag in P_FLAG temporarily +INVERSE_TMP: + and 1 + add a, a + add a, a; # Shift left 2 bits for temporary + ld hl, P_FLAG + res 2, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 15 "print.asm" +#line 1 "bold.asm" + + ; Sets BOLD flag in P_FLAG permanently +; Parameter: BOLD flag in bit 0 of A register + + +BOLD: + PROC + + and 1 + rlca + rlca + rlca + ld hl, FLAGS2 + res 3, (HL) + or (hl) + ld (hl), a + ret + + ; Sets BOLD flag in P_FLAG temporarily +BOLD_TMP: + and 1 + rlca + rlca + ld hl, FLAGS2 + res 2, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 16 "print.asm" +#line 1 "italic.asm" + + ; Sets ITALIC flag in P_FLAG permanently +; Parameter: ITALIC flag in bit 0 of A register + + +ITALIC: + PROC + + and 1 + rrca + rrca + rrca + ld hl, FLAGS2 + res 5, (HL) + or (hl) + ld (hl), a + ret + + ; Sets ITALIC flag in P_FLAG temporarily +ITALIC_TMP: + and 1 + rrca + rrca + rrca + rrca + ld hl, FLAGS2 + res 4, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 17 "print.asm" + +#line 1 "attr.asm" + + ; Attribute routines +; vim:ts=4:et:sw: + + + + + + + +__ATTR_ADDR: + ; calc start address in DE (as (32 * d) + e) + ; Contributed by Santiago Romero at http://www.speccy.org + ld h, 0 ; 7 T-States + ld a, d ; 4 T-States + add a, a ; a * 2 ; 4 T-States + add a, a ; a * 4 ; 4 T-States + ld l, a ; HL = A * 4 ; 4 T-States + + add hl, hl ; HL = A * 8 ; 15 T-States + add hl, hl ; HL = A * 16 ; 15 T-States + add hl, hl ; HL = A * 32 ; 15 T-States + + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) + add hl, de + + ld de, (SCREEN_ADDR) ; Adds the screen address + add hl, de + + ; Return current screen address in HL + ret + + + ; Sets the attribute at a given screen coordinate (D, E). + ; The attribute is taken from the ATTR_T memory variable + ; Used by PRINT routines +SET_ATTR: + + ; Checks for valid coords + call __IN_SCREEN + ret nc + +__SET_ATTR: + ; Internal __FASTCALL__ Entry used by printing routines + PROC + + call __ATTR_ADDR + ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T + + ld a, d + and (hl) + ld c, a ; C = current screen color, masked + + ld a, d + cpl ; Negate mask + and e ; Mask current attributes + or c ; Mix them + ld (hl), a ; Store result in screen + + ret + + ENDP + + +#line 19 "print.asm" + + ; Putting a comment starting with @INIT
+ ; will make the compiler to add a CALL to
+ ; It is useful for initialization routines. + + +__PRINT_INIT: ; To be called before program starts (initializes library) + PROC + + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + + ld hl, 1821h + ld (MAXX), hl ; Sets current maxX and maxY + + xor a + ld (FLAGS2), a + + ret + + +__PRINTCHAR: ; Print character store in accumulator (A register) + ; Modifies H'L', B'C', A'F', D'E', A + + LOCAL PO_GR_1 + + LOCAL __PRCHAR + LOCAL __PRINT_CONT + LOCAL __PRINT_CONT2 + LOCAL __PRINT_JUMP + LOCAL __SRCADDR + LOCAL __PRINT_UDG + LOCAL __PRGRAPH + LOCAL __PRINT_START + + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 + +__PRINT_JUMP: + jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively + +__PRINT_START: + cp ' ' + jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones + + exx ; Switch to alternative registers + ex af, af' ; Saves a value (char to print) for later + + call __LOAD_S_POSN + + ; At this point we have the new coord + ld hl, (SCREEN_ADDR) + + ld a, d + ld c, a ; Saves it for later + + and 0F8h ; Masks 3 lower bit ; zy + ld d, a + + ld a, c ; Recovers it + and 07h ; MOD 7 ; y1 + rrca + rrca + rrca + + or e + ld e, a + add hl, de ; HL = Screen address + DE + ex de, hl ; DE = Screen address + + ex af, af' + + cp 80h ; Is it an UDG or a ? + jp c, __SRCADDR + + cp 90h + jp nc, __PRINT_UDG + + ; Print a 8 bit pattern (80h to 8Fh) + + ld b, a + call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 + ld hl, MEM0 + jp __PRGRAPH + + PO_GR_1 EQU 0B38h + +__PRINT_UDG: + sub 90h ; Sub ASC code + ld bc, (UDG) + jp __PRGRAPH0 + + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source +__SRCADDR: + ld bc, (CHARS) + +__PRGRAPH0: + add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org + ld l, a + ld h, 0 ; HL = a * 2 (accumulator) + add hl, hl + add hl, hl ; HL = a * 8 + add hl, bc ; HL = CHARS address + +__PRGRAPH: + ex de, hl ; HL = Write Address, DE = CHARS address + bit 2, (iy + $47) + call nz, __BOLD + bit 4, (iy + $47) + call nz, __ITALIC + ld b, 8 ; 8 bytes per char +__PRCHAR: + ld a, (de) ; DE *must* be ALWAYS source, and HL destiny + +PRINT_MODE: ; Which operation is used to write on the screen + ; Set it with: + ; LD A, + ; LD (PRINT_MODE), A + ; + ; Available opertions: + ; NORMAL: 0h --> NOP ; OVER 0 + ; XOR : AEh --> XOR (HL) ; OVER 1 + ; OR : B6h --> OR (HL) ; PUTSPRITE + ; AND : A6h --> AND (HL) ; PUTMASK + nop ; + +INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 + nop ; 2F -> CPL -> INVERSE 1 + + ld (hl), a + + inc de + inc h ; Next line + djnz __PRCHAR + + call __LOAD_S_POSN + push de + call __SET_ATTR + pop de + inc e ; COL = COL + 1 + ld hl, (MAXX) + ld a, e + dec l ; l = MAXX + cp l ; Lower than max? + jp c, __PRINT_CONT; Nothing to do + call __PRINT_EOL1 + exx ; counteracts __PRINT_EOL1 exx + jp __PRINT_CONT2 + +__PRINT_CONT: + call __SAVE_S_POSN + +__PRINT_CONT2: + exx + ret + + ; ------------- SPECIAL CHARS (< 32) ----------------- + +__PRINT_SPECIAL: ; Jumps here if it is a special char + exx + ld hl, __PRINT_TABLE + jp JUMP_HL_PLUS_2A + + +PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence + exx + +__PRINT_0Dh: ; Called WHEN printing CHR$(13) + call __LOAD_S_POSN + +__PRINT_EOL1: ; Another entry called from PRINT when next line required + ld e, 0 + +__PRINT_EOL2: + ld a, d + inc a + +__PRINT_AT1_END: + ld hl, (MAXY) + cp l + jr c, __PRINT_EOL_END ; Carry if (MAXY) < d + xor a + +__PRINT_EOL_END: + ld d, a + +__PRINT_AT2_END: + call __SAVE_S_POSN + exx + ret + +__PRINT_COM: + exx + push hl + push de + push bc + call PRINT_COMMA + pop bc + pop de + pop hl + ret + +__PRINT_TAB: + ld hl, __PRINT_TAB1 + jp __PRINT_SET_STATE + +__PRINT_TAB1: + ld (MEM0), a + ld hl, __PRINT_TAB2 + ld (PRINT_JUMP_STATE), hl + ret + +__PRINT_TAB2: + ld a, (MEM0) ; Load tab code (ignore the current one) + push hl + push de + push bc + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + call PRINT_TAB + pop bc + pop de + pop hl + ret + +__PRINT_NOP: +__PRINT_RESTART: + ld hl, __PRINT_START + jp __PRINT_SET_STATE + +__PRINT_AT: + ld hl, __PRINT_AT1 + +__PRINT_SET_STATE: + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + exx + ret + +__PRINT_AT1: ; Jumps here if waiting for 1st parameter + exx + ld hl, __PRINT_AT2 + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + jp __PRINT_AT1_END + +__PRINT_AT2: + exx + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + ld e, a + ld hl, (MAXX) + cp (hl) + jr c, __PRINT_AT2_END + jr __PRINT_EOL1 + +__PRINT_DEL: + call __LOAD_S_POSN ; Gets current screen position + dec e + ld a, -1 + cp e + jp nz, __PRINT_AT2_END + ld hl, (MAXX) + ld e, l + dec e + dec e + dec d + cp d + jp nz, __PRINT_AT2_END + ld d, h + dec d + jp __PRINT_AT2_END + +__PRINT_INK: + ld hl, __PRINT_INK2 + jp __PRINT_SET_STATE + +__PRINT_INK2: + exx + call INK_TMP + jp __PRINT_RESTART + +__PRINT_PAP: + ld hl, __PRINT_PAP2 + jp __PRINT_SET_STATE + +__PRINT_PAP2: + exx + call PAPER_TMP + jp __PRINT_RESTART + +__PRINT_FLA: + ld hl, __PRINT_FLA2 + jp __PRINT_SET_STATE + +__PRINT_FLA2: + exx + call FLASH_TMP + jp __PRINT_RESTART + +__PRINT_BRI: + ld hl, __PRINT_BRI2 + jp __PRINT_SET_STATE + +__PRINT_BRI2: + exx + call BRIGHT_TMP + jp __PRINT_RESTART + +__PRINT_INV: + ld hl, __PRINT_INV2 + jp __PRINT_SET_STATE + +__PRINT_INV2: + exx + call INVERSE_TMP + jp __PRINT_RESTART + +__PRINT_OVR: + ld hl, __PRINT_OVR2 + jp __PRINT_SET_STATE + +__PRINT_OVR2: + exx + call OVER_TMP + jp __PRINT_RESTART + +__PRINT_BOLD: + ld hl, __PRINT_BOLD2 + jp __PRINT_SET_STATE + +__PRINT_BOLD2: + exx + call BOLD_TMP + jp __PRINT_RESTART + +__PRINT_ITA: + ld hl, __PRINT_ITA2 + jp __PRINT_SET_STATE + +__PRINT_ITA2: + exx + call ITALIC_TMP + jp __PRINT_RESTART + + +__BOLD: + push hl + ld hl, MEM0 + ld b, 8 +__BOLD_LOOP: + ld a, (de) + ld c, a + rlca + or c + ld (hl), a + inc hl + inc de + djnz __BOLD_LOOP + pop hl + ld de, MEM0 + ret + + +__ITALIC: + push hl + ld hl, MEM0 + ex de, hl + ld bc, 8 + ldir + ld hl, MEM0 + srl (hl) + inc hl + srl (hl) + inc hl + srl (hl) + inc hl + inc hl + inc hl + sla (hl) + inc hl + sla (hl) + inc hl + sla (hl) + pop hl + ld de, MEM0 + ret + +PRINT_COMMA: + call __LOAD_S_POSN + ld a, e + and 16 + add a, 16 + +PRINT_TAB: + PROC + LOCAL LOOP, CONTINUE + + inc a + call __LOAD_S_POSN ; e = current row + ld d, a + ld a, e + cp 21h + jr nz, CONTINUE + ld e, -1 +CONTINUE: + ld a, d + inc e + sub e ; A = A - E + and 31 ; + ret z ; Already at position E + ld b, a +LOOP: + ld a, ' ' + call __PRINTCHAR + djnz LOOP + ret + ENDP + +PRINT_AT: ; CHanges cursor to ROW, COL + ; COL in A register + ; ROW in stack + + pop hl ; Ret address + ex (sp), hl ; callee H = ROW + ld l, a + ex de, hl + + call __IN_SCREEN + ret nc ; Return if out of screen + + jp __SAVE_S_POSN + + LOCAL __PRINT_COM + LOCAL __BOLD + LOCAL __BOLD_LOOP + LOCAL __ITALIC + LOCAL __PRINT_EOL1 + LOCAL __PRINT_EOL2 + LOCAL __PRINT_AT1 + LOCAL __PRINT_AT2 + LOCAL __PRINT_AT2_END + LOCAL __PRINT_BOLD + LOCAL __PRINT_BOLD2 + LOCAL __PRINT_ITA + LOCAL __PRINT_ITA2 + LOCAL __PRINT_INK + LOCAL __PRINT_PAP + LOCAL __PRINT_SET_STATE + LOCAL __PRINT_TABLE + LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 + +__PRINT_TABLE: ; Jump table for 0 .. 22 codes + + DW __PRINT_NOP ; 0 + DW __PRINT_NOP ; 1 + DW __PRINT_NOP ; 2 + DW __PRINT_NOP ; 3 + DW __PRINT_NOP ; 4 + DW __PRINT_NOP ; 5 + DW __PRINT_COM ; 6 COMMA + DW __PRINT_NOP ; 7 + DW __PRINT_DEL ; 8 DEL + DW __PRINT_NOP ; 9 + DW __PRINT_NOP ; 10 + DW __PRINT_NOP ; 11 + DW __PRINT_NOP ; 12 + DW __PRINT_0Dh ; 13 + DW __PRINT_BOLD ; 14 + DW __PRINT_ITA ; 15 + DW __PRINT_INK ; 16 + DW __PRINT_PAP ; 17 + DW __PRINT_FLA ; 18 + DW __PRINT_BRI ; 19 + DW __PRINT_INV ; 20 + DW __PRINT_OVR ; 21 + DW __PRINT_AT ; 22 AT + DW __PRINT_TAB ; 23 TAB + + ENDP + + +#line 2 "printstr.asm" + + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 5 "printstr.asm" + + ; PRINT command routine + ; Prints string pointed by HL + +PRINT_STR: +__PRINTSTR: ; __FASTCALL__ Entry to print_string + PROC + LOCAL __PRINT_STR_LOOP + LOCAL __PRINT_STR_END + + ld d, a ; Saves A reg (Flag) for later + + ld a, h + or l + ret z ; Return if the pointer is NULL + + push hl + + ld c, (hl) + inc hl + ld b, (hl) + inc hl ; BC = LEN(a$); HL = &a$ + +__PRINT_STR_LOOP: + ld a, b + or c + jr z, __PRINT_STR_END ; END if BC (counter = 0) + + ld a, (hl) + call __PRINTCHAR + inc hl + dec bc + jp __PRINT_STR_LOOP + +__PRINT_STR_END: + pop hl + ld a, d ; Recovers A flag + or a ; If not 0 this is a temporary string. Free it + ret z + jp __MEM_FREE ; Frees str from heap and return from there + +__PRINT_STR: + ; Fastcall Entry + ; It ONLY prints strings + ; HL = String start + ; BC = String length (Number of chars) + push hl ; Push str address for later + ld d, a ; Saves a FLAG + jp __PRINT_STR_LOOP + + ENDP + +#line 81 "memcpytest.bas" + +ZXBASIC_USER_DATA: +_i: + DEFB 00 +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/memcpytest.bas b/tests/functional/memcpytest.bas new file mode 100644 index 000000000..e5a086286 --- /dev/null +++ b/tests/functional/memcpytest.bas @@ -0,0 +1,13 @@ + +CLS +FOR i = 1 to 10 + PRINT "TEST "; +NEXT + +#include + +memcopy(16384, 40000, 6912) +cls +pause 0 +memcopy(40000, 16384, 6912) + From 214c0d9041d979a565612883862398c1b0c47db4 Mon Sep 17 00:00:00 2001 From: Bartolome Sanchez Salado Date: Thu, 2 Nov 2017 23:12:52 +0100 Subject: [PATCH 099/247] Add basic HTML coverage --- .gitignore | 2 ++ tox.ini | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 280cb5e75..83c4055a5 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,5 @@ dist/ examples/*.bin examples/*.tzx scratch/ +.coverage +htmlcov/ diff --git a/tox.ini b/tox.ini index f976526fe..a8b0b6975 100644 --- a/tox.ini +++ b/tox.ini @@ -5,9 +5,10 @@ envlist = py27,py36,pypy,flake8 setenv = LANG=en_US.UTF-8 deps = pytest + pytest-cov -rrequirements.txt commands = - py.test {posargs} + py.test --cov-report html --cov . {posargs} [flake8] max-line-length = 120 From 932f895e5117da4cf0a984163f8d9cc08766ae9d Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 16 Oct 2017 23:16:34 +0200 Subject: [PATCH 100/247] update README.md file Removes .MSI reference, and put clearer instructions. Also adds logo (by @Haplo. Thanks!!) Thanks to @Hark0 for his suggestions. --- README.md | 52 ++++++++++++++++++++++++++++++++++++----------- zxbasic_logo.png | Bin 0 -> 624 bytes 2 files changed, 40 insertions(+), 12 deletions(-) create mode 100644 zxbasic_logo.png diff --git a/README.md b/README.md index 99eea23c4..1a8c8b57e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +![Boriel ZX Basic](./zxbasic_logo.png) + [![Build Status](https://travis-ci.org/boriel/zxbasic.svg?branch=master)](https://travis-ci.org/boriel/zxbasic) ZX BASIC @@ -30,34 +32,60 @@ For help, support, updates meet the community at my forum: -INSTALL -------- +INSTALLATION +------------ Go to the ZXBasic download page -and get the version most suitable for you. +and get the version most suitable for you. + +There are, basically, two flavors (both with identical capabilities): + + - For Windows you can download de win32 executable (Windows .exe zip package) version. +To install just uncompress it in a directory of your choice. +The main executable is `zxb.exe` (more on this later). With this toolchain +also comes `zxbasm.exe` (the assembler) and `zxbpp.exe` (the preprocessor), but these +are not needed when programming in BASIC. -These tools are completely written in python, so you will need a python -interpreter (available on many platforms). Just copy them in a directory of your -hoice and installation is done. :-) + - For Linux and Mac OSX there is a python version, so you will need a python +interpreter (available on many platforms, and usually already installed in Linux and Mac OSX). +Just uncompress it in a directory of your choice and installation is done. :-) +The main executables are `zxb.py` (the compiler), `zxbasm.py` (the assembler) and `zxbpp.py` (the preprocessor). +You can use this version in Windows, but will need to install a python interpreter first. -For Windows users there is also a binary .MSI installation, which does not need -python installed. +##### Examples +|![Eleuterio, el mono serio](http://www.boriel.com/wiki/en/images/a/ab/EleuterioElMonoSerio.gif)|![El Hobbit](http://www.boriel.com/wiki/en/images/7/72/HobbitEl.gif)|![Knight & Demonds DX](http://www.boriel.com/wiki/en/images/f/fe/KnightsDemonsDX.png)| +|---|---|---| +| An in-game screenshot of Eleuterio by @*na_th_an* | Ingame screenshot of _El Hobbit_ by @*Wilco2000*| Ingame screenshot of _Knignt and Demonds DX_ by Einar Saukas + +See more examples at http://www.boriel.com/wiki/en/index.php/ZX_BASIC:Released_Programs + QUICK START ----------- -For a quick start, just open a terminal in your PC (Windows) and type -`zxb` or `zxb.py` (OSX, Linux). You should see a zxbasic message. +For a quick start, just open a terminal in your PC in the same directory you uncompressed ZX Basic +and type `zxb` (on Windows) or `zxb.py` (OSX, Linux). You should see a zxbasic message like this: + +``` +usage: zxb [-h] [-d] [-O OPTIMIZE] [-o OUTPUT_FILE] [-T] [-t] [-B] [-a] [-A] + [-S ORG] [-e STDERR] [--array-base ARRAY_BASE] + [--string-base STRING_BASE] [-Z] [-H HEAP_SIZE] [--debug-memory] + [--debug-array] [--strict-bool] [--enable-break] [-E] [--explicit] + [-D DEFINES] [-M MEMORY_MAP] [-i] [-I INCLUDE_PATH] [--strict] + [--version] + PROGRAM +zxb: error: the following arguments are required: PROGRAM +``` -Create a text file, `hello.bas` with the following content: +Create a text file with the following content: ~~~~ 10 CLS 20 PRINT "HELLO WORLD!" ~~~~ -and compile it with: +Save it as `hello.bas` and finally compile it with: ~~~~ zxb -taB hello.bas ~~~~ diff --git a/zxbasic_logo.png b/zxbasic_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..1064b448842e396783bc4dd35beb9e05df3de13a GIT binary patch literal 624 zcmV-$0+0QPP)IVP-0sTot zK~#9!?cGgsgD?z+;keV2^vvzqy6aWwj$sk-uLwBLyJF!8lKDpZMwUrhmgNDQ#fP5& z1czz)T(8ns$PJc1KQd%E5F7{&2=j3L#;e=~rj#mNV6Jgf6)ie!_7-P`yhB|zM}F0-cZNT$30zqIlg@l|VE?_UB9tta;h>~qUTO|PcjxEwiQfSw zCL7^JCu^Qsh&f(nQ}U299F$ZL9B_t*>pzcF+M&F2g}d#neo3YAdF15;QH+R*Oyi0!k_f z4k++&<%XcfKBb@Bir=Gf%XiZgRvH literal 0 HcmV?d00001 From fae9c67d2288d8ca467c7320546e78c86f290cf7 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 3 Nov 2017 00:07:07 +0100 Subject: [PATCH 101/247] =?UTF-8?q?Bump=20version:=201.7.1=20=E2=86=92=201?= =?UTF-8?q?.7.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- ChangeLog | 6 ++++++ version.py | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index d7411a512..0303435e6 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,4 +1,4 @@ [bumpversion] -current_version = 1.7.1 +current_version = 1.7.2 files = version.py diff --git a/ChangeLog b/ChangeLog index b3b614ea8..2b2c9281a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +================================================================ +Changes from Version 1.7.1 to 1.7.2 +! Bugfixes in libraries esxdos.bas and memcopy.bas +* Improved pong.bas example +* Improved readme file :) (thanks to @harko and @haplo) + ================================================================ Changes from Version 1.7.0 to 1.7.1 ! Bugfixes with -O3 and DATA statements diff --git a/version.py b/version.py index f4dc8dec6..c9ec27fa7 100755 --- a/version.py +++ b/version.py @@ -1 +1 @@ -VERSION = '1.7.1' +VERSION = '1.7.2' From 128878911dd15dfe9880d78fb0583aee5dfc897c Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 3 Nov 2017 11:48:01 +0100 Subject: [PATCH 102/247] bugfix: potential crash upon error Fix a potential crash upon parsing error error --- zxbpp.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/zxbpp.py b/zxbpp.py index 5a085b129..e999aa764 100755 --- a/zxbpp.py +++ b/zxbpp.py @@ -244,8 +244,10 @@ def p_program_newline(p): tmp = [str(x()) if isinstance(x, MacroCall) else x for x in p[2]] except PreprocError as v: error(v.lineno, v.message) + p[0] = [] + return - p[0] = p[1] # + tmp # + [p[3]] + p[0] = p[1] p[0].extend(tmp) p[0].append(p[3]) From 9ec35cbf9a871201d7e9864bd728599c14580a6e Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 3 Nov 2017 09:48:50 +0100 Subject: [PATCH 103/247] add command line options to the preprocessor This allows specifying both input and output files, and the debug level. --- tests/functional/test.py | 65 ++++++++++++++++++++++++++++++---------- zxbpp.py | 39 ++++++++++++++++++++---- 2 files changed, 83 insertions(+), 21 deletions(-) diff --git a/tests/functional/test.py b/tests/functional/test.py index 4b6de32ed..30932ac5b 100755 --- a/tests/functional/test.py +++ b/tests/functional/test.py @@ -235,34 +235,67 @@ def updateTest(tfname, pattern_): f.write(''.join(lines)) -def testPREPRO(fname, pattern_=None): +def testPREPRO(fname, pattern_=None, inline=None): + """ Test preprocessing file. Test is done by preprocessing the file and then + comparing the output against an expected one. The output file can optionally be filtered + using a filter_ regexp (see above). + + :param fname: Filename (usually a .bi file) to test. + :param filter_: regexp for filtering output before comparing. It will be ignored for binary (tzx, tap, etc) files + :param inline: whether the test should be run inline or using the system shell + :return: True on success false if not + """ global UPDATE - tfname = os.path.join(TEMP_DIR, 'test' + fname + os.extsep + 'out') - prep = ' 2> /dev/null' if CLOSE_STDERR else '' - okfile = getName(fname) + os.extsep + 'out' - OPTIONS = '' - match = reOPT.match(getName(fname)) - if match: - OPTIONS = '-O' + match.groups()[0] + if inline is None: + inline = INLINE + + tfname = os.path.join(TEMP_DIR, 'test' + getName(fname) + os.extsep + 'out') + okfile = os.path.join(os.path.dirname(fname), getName(fname) + os.extsep + 'out') if UPDATE: tfname = okfile if os.path.exists(okfile): os.unlink(okfile) - syscmd = '{0} {1} {2} > {3}{4}'.format(ZXBPP, OPTIONS, fname, tfname, prep) + prep = ['-e', '/dev/null'] if CLOSE_STDERR else ['-e', STDERR] + if UPDATE: + tfname = okfile + if os.path.exists(okfile): + os.unlink(okfile) + + options = [os.path.basename(fname), '-o', tfname] + prep + if inline: + func = lambda: zxbpp.entry_point(options) + else: + cmdline = '{0} {1}'.format(ZXBPP, ' '.join(options)) + func = lambda: systemExec(cmdline) + result = None - with TempTestFile(lambda: systemExec(syscmd), tfname, UPDATE) as err_lvl: - if not UPDATE and not err_lvl: - result = is_same_file(okfile, tfname, replace_regexp=pattern_, - replace_what=ZXBASIC_ROOT, replace_with=_original_root) - else: - updateTest(tfname, pattern_) + try: + current_path = os.getcwd() + os.chdir(os.path.dirname(fname) or os.curdir) + + with TempTestFile(func, tfname, UPDATE): + if not UPDATE: + result = is_same_file(okfile, tfname, replace_regexp=pattern_, + replace_what=ZXBASIC_ROOT, replace_with=_original_root) + else: + updateTest(tfname, pattern_) + finally: + os.chdir(current_path) + return result def testASM(fname, inline=None): + """ Test assembling an ASM (.asm) file. Test is done by assembling the source code into a binary and then + comparing the output file against an expected binary output. + + :param fname: Filename (.asm file) to test. + :param inline: whether the test should be run inline or using the system shell + :return: True on success false if not + """ if inline is None: inline = INLINE @@ -343,7 +376,7 @@ def testFiles(file_list): elif ext == 'bas': result = testBAS(fname, filter_=FILTER, inline=INLINE) elif ext == 'bi': - result = testPREPRO(fname, pattern_=FILTER) + result = testPREPRO(fname, pattern_=FILTER, inline=INLINE) else: result = None diff --git a/zxbpp.py b/zxbpp.py index e999aa764..beff3efab 100755 --- a/zxbpp.py +++ b/zxbpp.py @@ -14,12 +14,14 @@ import sys import os import re +import argparse from zxbpplex import tokens # noqa import zxbpplex import zxbasmpplex from ply import yacc +import api from api.config import OPTIONS from api import global_ import api.utils @@ -91,10 +93,10 @@ def get_include_path(): f2 = os.path.basename(sys.executable).lower() # Executable filename # If executable filename and script name are the same, we are - if f1 == f2 or f2 == f1 + '.exe': # under a "compiled" py2exe binary + if f1 == f2 or f2 == f1 + '.exe': # under a "compiled" python binary result = os.path.dirname(os.path.realpath(sys.executable)) else: - result = os.path.dirname(os.path.realpath(sys.argv[0])) + result = os.path.dirname(os.path.realpath(__file__)) return result @@ -790,11 +792,38 @@ def main(argv): # ------- ERROR And Warning messages ---------------- -def entry_point(): +def entry_point(args=None): + if args is None: + args = sys.argv[1:] + + api.config.init() init() - result = main(sys.argv[1:]) + setMode('BASIC') + + parser = argparse.ArgumentParser() + parser.add_argument('-o', '--output', type=str, dest='output_file', default=None, + help='Sets output file. If not specified, will output to console (STDOUT)') + parser.add_argument('-d', '--debug', dest='debug', default=OPTIONS.Debug.value, action='count', + help='Enable verbosity/debugging output. Additional -d increase verbosity/debug level') + parser.add_argument('-e', '--errmsg', type=str, dest='stderr', default=None, + help='Error messages file (standard error console by default)') + parser.add_argument('input_file', type=str, default=None, nargs='?', + help="File to parse. If not specified, console input will be used (STDIN)") + + options = parser.parse_args(args=args) + OPTIONS.Debug.value = options.debug + + if options.stderr: + OPTIONS.StdErrFileName.value = options.stderr + OPTIONS.stderr.value = api.utils.open_file(OPTIONS.StdErrFileName.value, 'wt', 'utf-8') + + result = main([options.input_file] if options.input_file else []) if not global_.has_errors: # ok? - OPTIONS.stdout.value.write(OUTPUT) + if options.output_file: + with api.utils.open_file(options.output_file, 'wt', 'utf-8') as output_file: + output_file.write(OUTPUT) + else: + OPTIONS.stdout.value.write(OUTPUT) return result From 5b730d73c400189aadc23f6dfdbf11c2da8db5d5 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 3 Nov 2017 12:38:02 +0100 Subject: [PATCH 104/247] bugfix: correctly name program types --- tests/functional/test_asm.py | 2 +- tests/functional/test_prepro.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/functional/test_asm.py b/tests/functional/test_asm.py index e0220ba55..2b0613c33 100755 --- a/tests/functional/test_asm.py +++ b/tests/functional/test_asm.py @@ -19,4 +19,4 @@ def test_asm(fname): sys.stderr.write("Total: %i, Failed: %i (%3.2f%%)\n" % (test.COUNTER, test.FAILED, 100.0 * test.FAILED / float(test.COUNTER))) - assert test.EXIT_CODE == 0, "BASIC program test failed" + assert test.EXIT_CODE == 0, "ASM program test failed" diff --git a/tests/functional/test_prepro.py b/tests/functional/test_prepro.py index b16807649..06d00d8bc 100755 --- a/tests/functional/test_prepro.py +++ b/tests/functional/test_prepro.py @@ -18,4 +18,4 @@ def test_prepro(fname): sys.stderr.write("Total: %i, Failed: %i (%3.2f%%)\n" % (test.COUNTER, test.FAILED, 100.0 * test.FAILED / float(test.COUNTER))) - assert test.EXIT_CODE == 0, "BASIC program test failed" + assert test.EXIT_CODE == 0, "Preprocessor test failed" From af48a992593a078f6103e0b81e1a608ea7802101 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 5 Nov 2017 22:32:39 +0100 Subject: [PATCH 105/247] Use coverage only in py27 environment --- tox.ini | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index a8b0b6975..d0f2a5b67 100644 --- a/tox.ini +++ b/tox.ini @@ -8,7 +8,7 @@ deps = pytest-cov -rrequirements.txt commands = - py.test --cov-report html --cov . {posargs} + py.test . {posargs} [flake8] max-line-length = 120 @@ -27,6 +27,10 @@ exclude = deps = flake8 commands = flake8 +[testenv:py27] +commands = + py.test --cov-report html --cov . {posargs} + [travis] python = 3.6: py36, flake8 From e656f3bba3d3f1074d0a6fbe691b3dc400d6b61b Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 6 Nov 2017 23:22:22 +0100 Subject: [PATCH 106/247] refact: prevent potential bug when creating block This unifies the block creation and flattens it. --- symbols/block.py | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/symbols/block.py b/symbols/block.py index 0ecdc2149..c21e2ab89 100644 --- a/symbols/block.py +++ b/symbols/block.py @@ -6,7 +6,7 @@ # Copyleft (K), Jose M. Rodriguez-Rosa (a.k.a. Boriel) # # This program is Free Software and is released under the terms of -# the GNU General License +# the GNU General License v3 # ---------------------------------------------------------------------- from api.check import is_null @@ -14,29 +14,26 @@ class SymbolBLOCK(Symbol): - ''' Defines a block of code. - ''' + """ Defines a block of code. + """ def __init__(self, *nodes): Symbol.__init__(self, *(x for x in nodes if not is_null(x))) @classmethod def make_node(cls, *args): - ''' Creates a chain of code blocks. - ''' - args = [x for x in args if not is_null(x)] - if not args: - return SymbolBLOCK() # Empty block + """ Creates a chain of code blocks. + """ + new_args = [] + args = [x for x in args if not is_null(x)] for x in args: assert isinstance(x, Symbol) + if x.token == 'BLOCK': + new_args.extend(x.children) + else: + new_args.append(x) - if args[0].token == 'BLOCK': - args = args[0].children + args[1:] - - if args and args[-1].token == 'BLOCK': - args = args[:-1] + args[-1].children - - result = SymbolBLOCK(*tuple(args)) + result = SymbolBLOCK(*new_args) return result def __getitem__(self, item): From 29485634a14757cf89451f0d4d677a27a8be33fa Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 7 Nov 2017 12:36:00 +0100 Subject: [PATCH 107/247] Added badges to README.md file --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 1a8c8b57e..18e1c1353 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ ![Boriel ZX Basic](./zxbasic_logo.png) [![Build Status](https://travis-ci.org/boriel/zxbasic.svg?branch=master)](https://travis-ci.org/boriel/zxbasic) +[![license](https://img.shields.io/badge/License-GPLv3-blue.svg)](./LICENSE.txt) +[![pyversions](https://img.shields.io/pypi/pyversions/zxbasic.svg)](https://pypi.python.org/pypi/zxbasic) ZX BASIC -------- From 1e92902f136988a55d39eadc199a5541aa85c96a Mon Sep 17 00:00:00 2001 From: Bartolome Sanchez Salado Date: Tue, 7 Nov 2017 22:27:57 +0100 Subject: [PATCH 108/247] Exclude .tox folder from coverage --- .coveragerc | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .coveragerc diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 000000000..f3a5cd4ea --- /dev/null +++ b/.coveragerc @@ -0,0 +1,3 @@ +[run] +omit = + .tox/* From d8de9f153e757221212400a6fca8f6b9b8045947 Mon Sep 17 00:00:00 2001 From: Bartolome Sanchez Salado Date: Sun, 12 Nov 2017 21:07:14 +0100 Subject: [PATCH 109/247] Enable Coverage for all environments And split them in differents folders. --- tox.ini | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tox.ini b/tox.ini index d0f2a5b67..680ec0852 100644 --- a/tox.ini +++ b/tox.ini @@ -8,7 +8,10 @@ deps = pytest-cov -rrequirements.txt commands = - py.test . {posargs} + py.test \ + --cov-report html:htmlcov/{envname} \ + --cov . \ + {posargs} [flake8] max-line-length = 120 @@ -27,10 +30,6 @@ exclude = deps = flake8 commands = flake8 -[testenv:py27] -commands = - py.test --cov-report html --cov . {posargs} - [travis] python = 3.6: py36, flake8 From 65d7b615d2418e9664694d6a6e36b4a4e1429498 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 21 Nov 2017 15:45:17 +0100 Subject: [PATCH 110/247] bugfix: static math functions All constant math functions where being evaluated to SIN (instead of SIN, COS, TAN, SQR...) --- symbols/builtin.py | 13 ++-- tests/functional/constrig.asm | 113 ++++++++++++++++++++++++++++++++++ tests/functional/constrig.bas | 13 ++++ zxbparser.py | 15 +++-- 4 files changed, 144 insertions(+), 10 deletions(-) create mode 100644 tests/functional/constrig.asm create mode 100644 tests/functional/constrig.bas diff --git a/symbols/builtin.py b/symbols/builtin.py index 83c2711af..9c2eaad1f 100644 --- a/symbols/builtin.py +++ b/symbols/builtin.py @@ -18,8 +18,8 @@ class SymbolBUILTIN(Symbol): - ''' Defines an BUILTIN function e.g. INKEY$(), RND() or LEN - ''' + """ Defines an BUILTIN function e.g. INKEY$(), RND() or LEN + """ def __init__(self, lineno, fname, type_=None, *operands): assert isinstance(lineno, int) assert type_ is None or isinstance(type_, SymbolTYPE) @@ -60,24 +60,25 @@ def operands(self, value): @property def size(self): - ''' sizeof(type) - ''' + """ sizeof(type) + """ if self.type_ is None: return 0 return self.type_.size @classmethod def make_node(cls, lineno, fname, func=None, type_=None, *operands): - ''' Creates a node for a unary operation. E.g. -x or LEN(a$) + """ Creates a node for a unary operation. E.g. -x or LEN(a$) Parameters: -func: function used on constant folding when possible -type_: the resulting type (by default, the same as the argument). For example, for LEN (str$), result type is 'u16' and arg type is 'string' - ''' + """ if func is not None and len(operands) == 1: # Try constant-folding if is_number(operands[0]) or is_string(operands[0]): # e.g. ABS(-5) + print(func.__name__) return SymbolNUMBER(func(operands[0].value), type_=type_, lineno=lineno) return cls(lineno, fname, type_, *operands) diff --git a/tests/functional/constrig.asm b/tests/functional/constrig.asm new file mode 100644 index 000000000..d1e9be1de --- /dev/null +++ b/tests/functional/constrig.asm @@ -0,0 +1,113 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld a, 07Fh + ld de, 099B3h + ld bc, 0F5DBh + ld hl, _a + call __STOREF + ld a, 080h + ld de, 0BBEFh + ld bc, 01EA0h + ld hl, _a + call __STOREF + ld a, 07Fh + ld de, 0C93Fh + ld bc, 064B0h + ld hl, _a + call __STOREF + ld a, 07Dh + ld de, 0244Dh + ld bc, 0B093h + ld hl, _a + call __STOREF + ld a, 081h + ld de, 03D3Ch + ld bc, 06791h + ld hl, _a + call __STOREF + ld a, 07Fh + ld de, 03915h + ld bc, 030D3h + ld hl, _a + call __STOREF + ld a, 081h + ld de, 05A20h + ld bc, 07589h + ld hl, _a + call __STOREF + ld a, 086h + ld de, 07604h + ld bc, 00939h + ld hl, _a + call __STOREF + ld a, 081h + ld de, 0776Fh + ld bc, 08B50h + ld hl, _a + call __STOREF + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "storef.asm" + +__PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) + push de + ex de, hl ; DE <- HL + push ix + pop hl ; HL <- IX + add hl, de ; HL <- IX + HL + pop de + +__ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register + ex af, af' + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex af, af' + +__STOREF: ; Stores the given FP number in A EDCB at address HL + ld (hl), a + inc hl + ld (hl), e + inc hl + ld (hl), d + inc hl + ld (hl), c + inc hl + ld (hl), b + ret + +#line 63 "constrig.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 00, 00, 00, 00, 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/constrig.bas b/tests/functional/constrig.bas new file mode 100644 index 000000000..d66e88a2f --- /dev/null +++ b/tests/functional/constrig.bas @@ -0,0 +1,13 @@ + +DIM a as Float + +a = SIN(3.5) +a = COS(3.5) +a = TAN(3.5) +a = ASN(0.1) +a = ACS(0.1) +a = ATN(0.3) +a = LN(3.5) +a = EXP(3.5) +a = SQR(3.5) + diff --git a/zxbparser.py b/zxbparser.py index d6b65882d..0b637ede7 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -194,8 +194,6 @@ def make_builtin(lineno, fname, operands, func=None, type_=None): operands = [] assert isinstance(operands, Symbol) or isinstance(operands, tuple) or isinstance(operands, list) # TODO: In the future, builtin functions will be implemented in an external library, like POINT or ATTR - # HINT: They are not yet, because Sinclair BASIC grammar allows not to use parenthesis e.g. SIN x = SIN(x) - # HINT: which requires syntactical changes in the parser __DEBUG__('Creating BUILTIN "{}"'.format(fname), 1) if not isinstance(operands, collections.Iterable): operands = [operands] @@ -3211,12 +3209,21 @@ def p_sgn(p): # ---------------------------------------- # Trigonometrics and LN, EXP, SQR # ---------------------------------------- -def p_expr_sin(p): +def p_expr_trig(p): """ bexpr : math_fn bexpr %prec UMINUS """ p[0] = make_builtin(p.lineno(1), p[1], make_typecast(TYPE.float_, p[2], p.lineno(1)), - lambda x: math.sin(x)) + {'SIN': math.sin, + 'COS': math.cos, + 'TAN': math.tan, + 'ASN': math.asin, + 'ACS': math.acos, + 'ATN': math.atan, + 'LN': lambda y: math.log(y, math.exp(1)), # LN(x) + 'EXP': math.exp, + 'SQR': math.sqrt + }[p[1]]) def p_math_fn(p): From b11174baacc8fd6c717e5ac48087b7250986f293 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 21 Nov 2017 21:44:58 +0100 Subject: [PATCH 111/247] remove debug print --- symbols/builtin.py | 1 - 1 file changed, 1 deletion(-) diff --git a/symbols/builtin.py b/symbols/builtin.py index 9c2eaad1f..0b7d24980 100644 --- a/symbols/builtin.py +++ b/symbols/builtin.py @@ -78,7 +78,6 @@ def make_node(cls, lineno, fname, func=None, type_=None, *operands): """ if func is not None and len(operands) == 1: # Try constant-folding if is_number(operands[0]) or is_string(operands[0]): # e.g. ABS(-5) - print(func.__name__) return SymbolNUMBER(func(operands[0].value), type_=type_, lineno=lineno) return cls(lineno, fname, type_, *operands) From 06cc4993f3a1dfb2055102ac13fe76f78396f522 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 22 Nov 2017 11:41:31 +0100 Subject: [PATCH 112/247] make symbol NOP iterable Symbol NOP must be subclassed from BLOCK, since it's just an empty one. --- symbols/nop.py | 6 +++--- tests/symbols/test_symbolNOP.py | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 tests/symbols/test_symbolNOP.py diff --git a/symbols/nop.py b/symbols/nop.py index 60ef82c3d..2fc06c87e 100644 --- a/symbols/nop.py +++ b/symbols/nop.py @@ -9,12 +9,12 @@ # the GNU General License # ---------------------------------------------------------------------- -from .symbol_ import Symbol +from .block import SymbolBLOCK -class SymbolNOP(Symbol): +class SymbolNOP(SymbolBLOCK): def __init__(self): - Symbol.__init__(self) + super(SymbolNOP, self).__init__() def __bool__(self): return False diff --git a/tests/symbols/test_symbolNOP.py b/tests/symbols/test_symbolNOP.py new file mode 100644 index 000000000..dd63ec8b7 --- /dev/null +++ b/tests/symbols/test_symbolNOP.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from unittest import TestCase +from symbols import NOP + + +__author__ = 'boriel' + + +class TestSymbolBLOCK(TestCase): + def setUp(self): + self.nop = NOP() + + def test__len_0(self): + self.assertEqual(len(self.nop), 0, "NOP must have 0 length") + + def test__assert_false(self): + self.assertFalse(self.nop) From c88ee8ca643f2b1e6b669ff0832184db8cad8646 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 22 Nov 2017 23:21:59 +0100 Subject: [PATCH 113/247] code clean up. More PEP-8 compliant --- ast_/tree.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/ast_/tree.py b/ast_/tree.py index 69cdddd8e..9f5f5f3b6 100644 --- a/ast_/tree.py +++ b/ast_/tree.py @@ -10,9 +10,9 @@ class NotAnAstError(Error): - ''' Thrown when the "pointer" is not + """ Thrown when the "pointer" is not an AST, but another thing. - ''' + """ def __init__(self, instance): self.instance = instance self.msg = "Object '%s' is not an Ast instance" % str(instance) @@ -22,8 +22,8 @@ def __str__(self): class Tree(object): - ''' Simple tree implementation - ''' + """ Simple tree implementation + """ class childrenList(object): def __init__(self, node): assert isinstance(node, Tree) @@ -99,9 +99,9 @@ def children(self, value): self.children.append(x) def inorder(self, funct, stopOn=None): - ''' Iterates in order, calling the function with the current node. + """ Iterates in order, calling the function with the current node. If stopOn is set to True or False, it will stop on true or false. - ''' + """ if stopOn is None: for i in self.children: i.inorder(funct) @@ -113,9 +113,9 @@ def inorder(self, funct, stopOn=None): return funct(self) def preorder(self, funct, stopOn=None): - ''' Iterates in preorder, calling the function with the current node. + """ Iterates in preorder, calling the function with the current node. If stopOn is set to True or False, it will stop on true or false. - ''' + """ if funct(self.symbol) == stopOn and stopOn is not None: return stopOn @@ -128,9 +128,9 @@ def preorder(self, funct, stopOn=None): return stopOn def postorder(self, funct, stopOn=None): - ''' Iterates in postorder, calling the function with the current node. + """ Iterates in postorder, calling the function with the current node. If stopOn is set to True or False, it will stop on true or false. - ''' + """ if stopOn is None: for i in range(len(self.children) - 1, -1, -1): self.children[i].postorder(funct) @@ -141,20 +141,20 @@ def postorder(self, funct, stopOn=None): return funct(self.symbol) def appendChild(self, node): - ''' Appends the given node to the current children list - ''' + """ Appends the given node to the current children list + """ self.children.append(node) def prependChild(self, node): - ''' Inserts the given node at the beginning of the children list - ''' + """ Inserts the given node at the beginning of the children list + """ self.children.insert(0, node) @classmethod def makenode(clss, symbol, *nexts): - ''' Stores the symbol in an AST instance, + """ Stores the symbol in an AST instance, and left and right to the given ones - ''' + """ result = clss(symbol) for i in nexts: if i is None: From 5bcca4b5b8a18d2617081574e0999ec578476b3c Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 6 Nov 2017 23:23:35 +0100 Subject: [PATCH 114/247] Refact: simplify grammar This also allows omitting END IF in one-line ifs --- api/errmsg.py | 6 + arch/zx48k/translator.py | 1 + symbols/sentence.py | 5 +- tests/functional/co.asm | 35 + tests/functional/co.bas | 2 + tests/functional/doloop4.asm | 41 + tests/functional/doloop4.bas | 8 + tests/functional/doloopuntilsplitted.bas | 6 + tests/functional/dountilempty.asm | 73 ++ tests/functional/dountilempty.bas | 4 + tests/functional/dountilsplitted.asm | 376 ++++++ tests/functional/dountilsplitted.bas | 6 + tests/functional/dowhileempty.asm | 73 ++ tests/functional/dowhileempty.bas | 5 + tests/functional/dowhilesplitted.asm | 376 ++++++ tests/functional/dowhilesplitted.bas | 6 + tests/functional/elseif5.asm | 5 +- tests/functional/elseif6.asm | 6 +- tests/functional/forline.bas | 2 + tests/functional/forsplitted.asm | 73 ++ tests/functional/forsplitted.bas | 5 + tests/functional/forsplitted0.asm | 85 ++ tests/functional/forsplitted0.bas | 4 + tests/functional/forsplitted1.asm | 71 ++ tests/functional/forsplitted1.bas | 5 + tests/functional/funcif.asm | 197 ++++ tests/functional/funcif.bas | 10 + tests/functional/ifelse2.asm | 92 ++ tests/functional/ifelse2.bas | 5 + tests/functional/ifelse3.asm | 78 ++ tests/functional/ifelse3.bas | 4 + tests/functional/ifelse4.asm | 78 ++ tests/functional/ifelse4.bas | 8 + tests/functional/ifelse5.asm | 87 ++ tests/functional/ifelse5.bas | 4 + tests/functional/ifemptyelse.asm | 40 + tests/functional/ifemptyelse.bas | 5 + tests/functional/ifendif.bas | 6 + tests/functional/iffor.asm | 85 ++ tests/functional/iffor.bas | 5 + tests/functional/iffor1.asm | 85 ++ tests/functional/iffor1.bas | 6 + tests/functional/iffor2.asm | 107 ++ tests/functional/iffor2.bas | 10 + tests/functional/ififelseelse1.asm | 98 ++ tests/functional/ififelseelse1.bas | 4 + tests/functional/ififelseelse2.asm | 98 ++ tests/functional/ififelseelse2.bas | 4 + tests/functional/ifline.asm | 44 + tests/functional/ifline.bas | 5 + tests/functional/ifthenelse.asm | 2 +- tests/functional/ifthenelseif.asm | 4 +- tests/functional/ifwhile.asm | 81 ++ tests/functional/ifwhile.bas | 6 + tests/functional/ifwhile1.asm | 81 ++ tests/functional/ifwhile1.bas | 7 + tests/functional/ifwhilex.asm | 1374 ++++++++++++++++++++++ tests/functional/ifwhilex.bas | 7 + tests/functional/label_sent.asm | 36 + tests/functional/label_sent.bas | 2 + tests/functional/label_sent1.asm | 49 + tests/functional/label_sent1.bas | 3 + tests/functional/label_sent2.asm | 157 +++ tests/functional/label_sent2.bas | 3 + tests/functional/label_sent3.asm | 157 +++ tests/functional/label_sent3.bas | 3 + tests/functional/label_sent4.asm | 157 +++ tests/functional/label_sent4.bas | 3 + tests/functional/label_sent5.asm | 157 +++ tests/functional/label_sent5.bas | 3 + tests/functional/labeldecl.asm | 43 + tests/functional/labeldecl.bas | 5 + tests/functional/labelsent.asm | 189 +++ tests/functional/labelsent.bas | 4 + tests/functional/whileempty.bas | 3 + tests/functional/whileempty1.asm | 71 ++ tests/functional/whileempty1.bas | 4 + tests/functional/whilesplitted.asm | 374 ++++++ tests/functional/whilesplitted.bas | 7 + zxblex.py | 1 - zxbparser.py | 856 +++++++------- 81 files changed, 5851 insertions(+), 442 deletions(-) create mode 100644 tests/functional/co.asm create mode 100644 tests/functional/co.bas create mode 100644 tests/functional/doloop4.asm create mode 100644 tests/functional/doloop4.bas create mode 100644 tests/functional/doloopuntilsplitted.bas create mode 100644 tests/functional/dountilempty.asm create mode 100644 tests/functional/dountilempty.bas create mode 100644 tests/functional/dountilsplitted.asm create mode 100644 tests/functional/dountilsplitted.bas create mode 100644 tests/functional/dowhileempty.asm create mode 100644 tests/functional/dowhileempty.bas create mode 100644 tests/functional/dowhilesplitted.asm create mode 100644 tests/functional/dowhilesplitted.bas create mode 100644 tests/functional/forline.bas create mode 100644 tests/functional/forsplitted.asm create mode 100644 tests/functional/forsplitted.bas create mode 100644 tests/functional/forsplitted0.asm create mode 100644 tests/functional/forsplitted0.bas create mode 100644 tests/functional/forsplitted1.asm create mode 100644 tests/functional/forsplitted1.bas create mode 100644 tests/functional/funcif.asm create mode 100644 tests/functional/funcif.bas create mode 100644 tests/functional/ifelse2.asm create mode 100644 tests/functional/ifelse2.bas create mode 100644 tests/functional/ifelse3.asm create mode 100644 tests/functional/ifelse3.bas create mode 100644 tests/functional/ifelse4.asm create mode 100644 tests/functional/ifelse4.bas create mode 100644 tests/functional/ifelse5.asm create mode 100644 tests/functional/ifelse5.bas create mode 100644 tests/functional/ifemptyelse.asm create mode 100644 tests/functional/ifemptyelse.bas create mode 100644 tests/functional/ifendif.bas create mode 100644 tests/functional/iffor.asm create mode 100644 tests/functional/iffor.bas create mode 100644 tests/functional/iffor1.asm create mode 100644 tests/functional/iffor1.bas create mode 100644 tests/functional/iffor2.asm create mode 100644 tests/functional/iffor2.bas create mode 100644 tests/functional/ififelseelse1.asm create mode 100644 tests/functional/ififelseelse1.bas create mode 100644 tests/functional/ififelseelse2.asm create mode 100644 tests/functional/ififelseelse2.bas create mode 100644 tests/functional/ifline.asm create mode 100644 tests/functional/ifline.bas create mode 100644 tests/functional/ifwhile.asm create mode 100644 tests/functional/ifwhile.bas create mode 100644 tests/functional/ifwhile1.asm create mode 100644 tests/functional/ifwhile1.bas create mode 100644 tests/functional/ifwhilex.asm create mode 100644 tests/functional/ifwhilex.bas create mode 100644 tests/functional/label_sent.asm create mode 100644 tests/functional/label_sent.bas create mode 100644 tests/functional/label_sent1.asm create mode 100644 tests/functional/label_sent1.bas create mode 100644 tests/functional/label_sent2.asm create mode 100644 tests/functional/label_sent2.bas create mode 100644 tests/functional/label_sent3.asm create mode 100644 tests/functional/label_sent3.bas create mode 100644 tests/functional/label_sent4.asm create mode 100644 tests/functional/label_sent4.bas create mode 100644 tests/functional/label_sent5.asm create mode 100644 tests/functional/label_sent5.bas create mode 100644 tests/functional/labeldecl.asm create mode 100644 tests/functional/labeldecl.bas create mode 100644 tests/functional/labelsent.asm create mode 100644 tests/functional/labelsent.bas create mode 100644 tests/functional/whileempty.bas create mode 100644 tests/functional/whileempty1.asm create mode 100644 tests/functional/whileempty1.bas create mode 100644 tests/functional/whilesplitted.asm create mode 100644 tests/functional/whilesplitted.bas diff --git a/api/errmsg.py b/api/errmsg.py index f41480c18..ac58ae279 100644 --- a/api/errmsg.py +++ b/api/errmsg.py @@ -73,6 +73,12 @@ def warning_empty_loop(lineno): warning(lineno, 'Empty loop') +def warning_empty_if(lineno): + """ Warning: Useless empty IF ignored + """ + warning(lineno, 'Useless empty IF ignored') + + # Emmits an optimization warning def warning_not_used(lineno, id_, kind='Variable'): if OPTIONS.optimization.value > 0: diff --git a/arch/zx48k/translator.py b/arch/zx48k/translator.py index 06ce2e5c4..838269e53 100644 --- a/arch/zx48k/translator.py +++ b/arch/zx48k/translator.py @@ -824,6 +824,7 @@ def visit_CHKBREAK(self, node): backend.REQUIRES.add('break.asm') def visit_IF(self, node): + assert 1 < len(node.children) < 4 yield node.children[0] if_label_else = backend.tmp_label() if_label_endif = backend.tmp_label() diff --git a/symbols/sentence.py b/symbols/sentence.py index 3bcb4241a..d5c671e1c 100644 --- a/symbols/sentence.py +++ b/symbols/sentence.py @@ -6,11 +6,10 @@ # Copyleft (K), Jose M. Rodriguez-Rosa (a.k.a. Boriel) # # This program is Free Software and is released under the terms of -# the GNU General License +# the GNU General License v3 # ---------------------------------------------------------------------- from .symbol_ import Symbol -from api.check import is_null class SymbolSENTENCE(Symbol): @@ -19,7 +18,7 @@ class SymbolSENTENCE(Symbol): def __init__(self, keyword, *args): """ keyword = 'BORDER', or 'PRINT' """ - Symbol.__init__(self, *(x for x in args if not is_null(x))) + super(SymbolSENTENCE, self).__init__(*(x for x in args if x is not None)) self.keyword = keyword @property diff --git a/tests/functional/co.asm b/tests/functional/co.asm new file mode 100644 index 000000000..9e4b187ec --- /dev/null +++ b/tests/functional/co.asm @@ -0,0 +1,35 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/co.bas b/tests/functional/co.bas new file mode 100644 index 000000000..871064241 --- /dev/null +++ b/tests/functional/co.bas @@ -0,0 +1,2 @@ +: + diff --git a/tests/functional/doloop4.asm b/tests/functional/doloop4.asm new file mode 100644 index 000000000..9beded5f0 --- /dev/null +++ b/tests/functional/doloop4.asm @@ -0,0 +1,41 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei +__LABEL__10: +__LABEL0: +__LABEL__20: + jp __LABEL0 +__LABEL1: + jp __LABEL__20 + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/doloop4.bas b/tests/functional/doloop4.bas new file mode 100644 index 000000000..f0bf9f652 --- /dev/null +++ b/tests/functional/doloop4.bas @@ -0,0 +1,8 @@ +REM DO..LOOP syntax test + + +10 DO +20 LOOP + +GOTO 20 + diff --git a/tests/functional/doloopuntilsplitted.bas b/tests/functional/doloopuntilsplitted.bas new file mode 100644 index 000000000..824b12214 --- /dev/null +++ b/tests/functional/doloopuntilsplitted.bas @@ -0,0 +1,6 @@ + +DO +LET M=0: LOOP UNTIL i=1 + +DO LET M=0: LOOP UNTIL i=1 + diff --git a/tests/functional/dountilempty.asm b/tests/functional/dountilempty.asm new file mode 100644 index 000000000..af6f7511f --- /dev/null +++ b/tests/functional/dountilempty.asm @@ -0,0 +1,73 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + jp __LABEL2 +__LABEL0: +__LABEL2: + ld a, 10 + ld hl, (_i - 1) + call __LTI8 + or a + jp z, __LABEL0 +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "lti8.asm" + +#line 1 "lei8.asm" + +__LEI8: ; Signed <= comparison for 8bit int + ; A <= H (registers) + PROC + LOCAL checkParity + sub h + jr nz, __LTI + inc a + ret + +__LTI8: ; Test 8 bit values A < H + sub h + +__LTI: ; Generic signed comparison + jp po, checkParity + xor 0x80 +checkParity: + ld a, 0 ; False + ret p + inc a ; True + ret + ENDP +#line 2 "lti8.asm" +#line 27 "dountilempty.bas" + +ZXBASIC_USER_DATA: +_i: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/dountilempty.bas b/tests/functional/dountilempty.bas new file mode 100644 index 000000000..14b3b891a --- /dev/null +++ b/tests/functional/dountilempty.bas @@ -0,0 +1,4 @@ + +DIM i as Byte +DO UNTIL i > 10 LOOP + diff --git a/tests/functional/dountilsplitted.asm b/tests/functional/dountilsplitted.asm new file mode 100644 index 000000000..4459e4f7a --- /dev/null +++ b/tests/functional/dountilsplitted.asm @@ -0,0 +1,376 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + jp __LABEL2 +__LABEL0: + xor a + ld (_M), a +__LABEL2: + ld hl, _i + 4 + call __FP_PUSH_REV + ld a, 081h + ld de, 00000h + ld bc, 00000h + call __EQF + or a + jp z, __LABEL0 +__LABEL1: + jp __LABEL5 +__LABEL3: + xor a + ld (_M), a +__LABEL5: + ld hl, _i + 4 + call __FP_PUSH_REV + ld a, 081h + ld de, 00000h + ld bc, 00000h + call __EQF + or a + jp z, __LABEL3 +__LABEL4: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "eqf.asm" + +#line 1 "u32tofreg.asm" + +#line 1 "neg32.asm" + +__ABS32: + bit 7, d + ret z + +__NEG32: ; Negates DEHL (Two's complement) + ld a, l + cpl + ld l, a + + ld a, h + cpl + ld h, a + + ld a, e + cpl + ld e, a + + ld a, d + cpl + ld d, a + + inc l + ret nz + + inc h + ret nz + + inc de + ret + +#line 2 "u32tofreg.asm" +__I8TOFREG: + ld l, a + rlca + sbc a, a ; A = SGN(A) + ld h, a + ld e, a + ld d, a + +__I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) + ; to a Floating Point Number returned in (A ED CB) + + ld a, d + or a ; Test sign + + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __U32TOFREG ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + +__U8TOFREG: + ; Converts an unsigned 8 bit (A) to Floating point + ld l, a + ld h, 0 + ld e, h + ld d, h + +__U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in A ED CB + + PROC + + LOCAL __U32TOFREG_END + + ld a, d + or e + or h + or l + ld b, d + ld c, e ; Returns 00 0000 0000 if ZERO + ret z + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 128 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + +__U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG + exx + ld a, d ; B'C'D'E' == 0 ? + or e + or b + or c + jp z, __U32TOFREG_END ; We are done + + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry + rr c + rr d + rr e + exx + + rr e ; Shift EDCB >> 1, inserting the carry on the left + rr d + rr c + rr b + + inc l ; Increment exponent + jp __U32TOFREG_LOOP + + +__U32TOFREG_END: + exx + ld a, l ; Puts the exponent in a + res 7, e ; Sets the sign bit to 0 (positive) + + ret + ENDP + +#line 2 "eqf.asm" +#line 1 "ftou32reg.asm" + + + +__FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + ; Output: DEHL 32 bit number (signed) + PROC + + LOCAL __IS_FLOAT + + or a + jr nz, __IS_FLOAT + ; Here if it is a ZX ROM Integer + + ld h, c + ld l, d + ld a, e ; Takes sign: FF = -, 0 = + + ld de, 0 + inc a + jp z, __NEG32 ; Negates if negative + ret + +__IS_FLOAT: ; Jumps here if it is a true floating point number + ld h, e + push hl ; Stores it for later (Contains Sign in H) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + ;ld a, c ; Get exponent + sub 128 ; Exponent -= 128 + jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + +__FTOU32REG_LOOP: + exx ; Shift C'B' E'D' << 1, output bit stays in Carry + sla d + rl e + rl b + rl c + + exx ; Shift DEHL << 1, inserting the carry on the right + rl l + rl h + rl e + rl d + + djnz __FTOU32REG_LOOP + +__FTOU32REG_END: + pop af ; Take the sign bit + or a ; Sets SGN bit to 1 if negative + jp m, __NEG32 ; Negates DEHL + + ret + + ENDP + + +__FTOU8: ; Converts float in C ED LH to Unsigned byte in A + call __FTOU32REG + ld a, l + ret + +#line 3 "eqf.asm" +#line 1 "stackf.asm" + + ; ------------------------------------------------------------- + ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC + ; ------------------------------------------------------------- + + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) + __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) + +__FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) + ; Second argument to push into the stack calculator is popped out of the stack + ; Since the caller routine also receives the parameters into the top of the stack + ; four bytes must be removed from SP before pop them out + + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK + exx + pop hl ; Caller-Caller return addr + exx + pop hl ; Caller return addr + + pop af + pop de + pop bc + + push hl ; Caller return addr + exx + push hl ; Caller-Caller return addr + exx + + jp __FPSTACK_PUSH + + +__FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK + ; This format is specified in the ZX 48K Manual + ; You can push a 16 bit signed integer as + ; 0 SS LL HH 0, being SS the sign and LL HH the low + ; and High byte respectively + ld a, h + rla ; sign to Carry + sbc a, a ; 0 if positive, FF if negative + ld e, a + ld d, l + ld c, h + xor a + ld b, a + jp __FPSTACK_PUSH +#line 4 "eqf.asm" + + ; ------------------------------------------------------------- + ; Floating point library using the FP ROM Calculator (ZX 48K) + + ; All of them uses C EDHL registers as 1st paramter. + ; For binary operators, the 2n operator must be pushed into the + ; stack, in the order BC DE HL (B not used). + ; + ; Uses CALLEE convention + ; ------------------------------------------------------------- + + +__EQF: ; A = B + call __FPSTACK_PUSH2 + + ; ------------- ROM NOS-EQL + ld b, 0Eh ; For comparison operators, OP must be in B also + rst 28h + defb 0Eh + defb 38h; ; END CALC + + call __FPSTACK_POP + jp __FTOU8 ; Convert to 8 bits + +#line 46 "dountilsplitted.bas" +#line 1 "pushf.asm" + + + ; Routine to push Float pointed by HL + ; Into the stack. Notice that the hl points to the last + ; byte of the FP number. + ; Uses H'L' B'C' and D'E' to preserve ABCDEHL registers + +__FP_PUSH_REV: + push hl + exx + pop hl + pop bc ; Return Address + ld d, (hl) + dec hl + ld e, (hl) + dec hl + push de + ld d, (hl) + dec hl + ld e, (hl) + dec hl + push de + ld d, (hl) + push de + push bc ; Return Address + exx + ret + + +#line 47 "dountilsplitted.bas" + +ZXBASIC_USER_DATA: +_i: + DEFB 00, 00, 00, 00, 00 +_M: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/dountilsplitted.bas b/tests/functional/dountilsplitted.bas new file mode 100644 index 000000000..fae94b004 --- /dev/null +++ b/tests/functional/dountilsplitted.bas @@ -0,0 +1,6 @@ + +DO UNTIL i=1: +LET M=0: LOOP + +DO UNTIL i=1: LET M=0: LOOP + diff --git a/tests/functional/dowhileempty.asm b/tests/functional/dowhileempty.asm new file mode 100644 index 000000000..ef8d37c25 --- /dev/null +++ b/tests/functional/dowhileempty.asm @@ -0,0 +1,73 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + jp __LABEL2 +__LABEL0: +__LABEL2: + ld h, 10 + ld a, (_i) + call __LTI8 + or a + jp nz, __LABEL0 +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "lti8.asm" + +#line 1 "lei8.asm" + +__LEI8: ; Signed <= comparison for 8bit int + ; A <= H (registers) + PROC + LOCAL checkParity + sub h + jr nz, __LTI + inc a + ret + +__LTI8: ; Test 8 bit values A < H + sub h + +__LTI: ; Generic signed comparison + jp po, checkParity + xor 0x80 +checkParity: + ld a, 0 ; False + ret p + inc a ; True + ret + ENDP +#line 2 "lti8.asm" +#line 27 "dowhileempty.bas" + +ZXBASIC_USER_DATA: +_i: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/dowhileempty.bas b/tests/functional/dowhileempty.bas new file mode 100644 index 000000000..305c84849 --- /dev/null +++ b/tests/functional/dowhileempty.bas @@ -0,0 +1,5 @@ + +DIM i as Byte + +DO WHILE i < 10 LOOP + diff --git a/tests/functional/dowhilesplitted.asm b/tests/functional/dowhilesplitted.asm new file mode 100644 index 000000000..44726bab0 --- /dev/null +++ b/tests/functional/dowhilesplitted.asm @@ -0,0 +1,376 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + jp __LABEL2 +__LABEL0: + xor a + ld (_M), a +__LABEL2: + ld hl, _i + 4 + call __FP_PUSH_REV + ld a, 081h + ld de, 00000h + ld bc, 00000h + call __EQF + or a + jp nz, __LABEL0 +__LABEL1: + jp __LABEL5 +__LABEL3: + xor a + ld (_M), a +__LABEL5: + ld hl, _i + 4 + call __FP_PUSH_REV + ld a, 081h + ld de, 00000h + ld bc, 00000h + call __EQF + or a + jp nz, __LABEL3 +__LABEL4: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "eqf.asm" + +#line 1 "u32tofreg.asm" + +#line 1 "neg32.asm" + +__ABS32: + bit 7, d + ret z + +__NEG32: ; Negates DEHL (Two's complement) + ld a, l + cpl + ld l, a + + ld a, h + cpl + ld h, a + + ld a, e + cpl + ld e, a + + ld a, d + cpl + ld d, a + + inc l + ret nz + + inc h + ret nz + + inc de + ret + +#line 2 "u32tofreg.asm" +__I8TOFREG: + ld l, a + rlca + sbc a, a ; A = SGN(A) + ld h, a + ld e, a + ld d, a + +__I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) + ; to a Floating Point Number returned in (A ED CB) + + ld a, d + or a ; Test sign + + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __U32TOFREG ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + +__U8TOFREG: + ; Converts an unsigned 8 bit (A) to Floating point + ld l, a + ld h, 0 + ld e, h + ld d, h + +__U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in A ED CB + + PROC + + LOCAL __U32TOFREG_END + + ld a, d + or e + or h + or l + ld b, d + ld c, e ; Returns 00 0000 0000 if ZERO + ret z + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 128 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + +__U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG + exx + ld a, d ; B'C'D'E' == 0 ? + or e + or b + or c + jp z, __U32TOFREG_END ; We are done + + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry + rr c + rr d + rr e + exx + + rr e ; Shift EDCB >> 1, inserting the carry on the left + rr d + rr c + rr b + + inc l ; Increment exponent + jp __U32TOFREG_LOOP + + +__U32TOFREG_END: + exx + ld a, l ; Puts the exponent in a + res 7, e ; Sets the sign bit to 0 (positive) + + ret + ENDP + +#line 2 "eqf.asm" +#line 1 "ftou32reg.asm" + + + +__FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + ; Output: DEHL 32 bit number (signed) + PROC + + LOCAL __IS_FLOAT + + or a + jr nz, __IS_FLOAT + ; Here if it is a ZX ROM Integer + + ld h, c + ld l, d + ld a, e ; Takes sign: FF = -, 0 = + + ld de, 0 + inc a + jp z, __NEG32 ; Negates if negative + ret + +__IS_FLOAT: ; Jumps here if it is a true floating point number + ld h, e + push hl ; Stores it for later (Contains Sign in H) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + ;ld a, c ; Get exponent + sub 128 ; Exponent -= 128 + jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + +__FTOU32REG_LOOP: + exx ; Shift C'B' E'D' << 1, output bit stays in Carry + sla d + rl e + rl b + rl c + + exx ; Shift DEHL << 1, inserting the carry on the right + rl l + rl h + rl e + rl d + + djnz __FTOU32REG_LOOP + +__FTOU32REG_END: + pop af ; Take the sign bit + or a ; Sets SGN bit to 1 if negative + jp m, __NEG32 ; Negates DEHL + + ret + + ENDP + + +__FTOU8: ; Converts float in C ED LH to Unsigned byte in A + call __FTOU32REG + ld a, l + ret + +#line 3 "eqf.asm" +#line 1 "stackf.asm" + + ; ------------------------------------------------------------- + ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC + ; ------------------------------------------------------------- + + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) + __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) + +__FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) + ; Second argument to push into the stack calculator is popped out of the stack + ; Since the caller routine also receives the parameters into the top of the stack + ; four bytes must be removed from SP before pop them out + + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK + exx + pop hl ; Caller-Caller return addr + exx + pop hl ; Caller return addr + + pop af + pop de + pop bc + + push hl ; Caller return addr + exx + push hl ; Caller-Caller return addr + exx + + jp __FPSTACK_PUSH + + +__FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK + ; This format is specified in the ZX 48K Manual + ; You can push a 16 bit signed integer as + ; 0 SS LL HH 0, being SS the sign and LL HH the low + ; and High byte respectively + ld a, h + rla ; sign to Carry + sbc a, a ; 0 if positive, FF if negative + ld e, a + ld d, l + ld c, h + xor a + ld b, a + jp __FPSTACK_PUSH +#line 4 "eqf.asm" + + ; ------------------------------------------------------------- + ; Floating point library using the FP ROM Calculator (ZX 48K) + + ; All of them uses C EDHL registers as 1st paramter. + ; For binary operators, the 2n operator must be pushed into the + ; stack, in the order BC DE HL (B not used). + ; + ; Uses CALLEE convention + ; ------------------------------------------------------------- + + +__EQF: ; A = B + call __FPSTACK_PUSH2 + + ; ------------- ROM NOS-EQL + ld b, 0Eh ; For comparison operators, OP must be in B also + rst 28h + defb 0Eh + defb 38h; ; END CALC + + call __FPSTACK_POP + jp __FTOU8 ; Convert to 8 bits + +#line 46 "dowhilesplitted.bas" +#line 1 "pushf.asm" + + + ; Routine to push Float pointed by HL + ; Into the stack. Notice that the hl points to the last + ; byte of the FP number. + ; Uses H'L' B'C' and D'E' to preserve ABCDEHL registers + +__FP_PUSH_REV: + push hl + exx + pop hl + pop bc ; Return Address + ld d, (hl) + dec hl + ld e, (hl) + dec hl + push de + ld d, (hl) + dec hl + ld e, (hl) + dec hl + push de + ld d, (hl) + push de + push bc ; Return Address + exx + ret + + +#line 47 "dowhilesplitted.bas" + +ZXBASIC_USER_DATA: +_i: + DEFB 00, 00, 00, 00, 00 +_M: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/dowhilesplitted.bas b/tests/functional/dowhilesplitted.bas new file mode 100644 index 000000000..d14789f40 --- /dev/null +++ b/tests/functional/dowhilesplitted.bas @@ -0,0 +1,6 @@ + +DO WHILE i=1: +LET M=0: LOOP + +DO WHILE i=1: LET M=0: LOOP + diff --git a/tests/functional/elseif5.asm b/tests/functional/elseif5.asm index 597b198af..7a476ab02 100644 --- a/tests/functional/elseif5.asm +++ b/tests/functional/elseif5.asm @@ -20,7 +20,8 @@ __LABEL0: ld hl, (_a - 1) call __LTI8 or a - jp z, __LABEL3 + jp nz, __LABEL3 +__LABEL2: ld a, (_a) or a jp nz, __LABEL5 @@ -72,7 +73,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 38 "elseif5.bas" +#line 39 "elseif5.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/elseif6.asm b/tests/functional/elseif6.asm index 667da2109..39dacd128 100644 --- a/tests/functional/elseif6.asm +++ b/tests/functional/elseif6.asm @@ -14,10 +14,12 @@ __START_PROGRAM: ld a, (_a) call __LTI8 or a - jp z, __LABEL1 + jp z, __LABEL0 ld a, (_a) inc a ld (_a), a + jp __LABEL1 +__LABEL0: __LABEL1: ld hl, 0 ld b, h @@ -61,7 +63,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 27 "elseif6.bas" +#line 29 "elseif6.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/forline.bas b/tests/functional/forline.bas new file mode 100644 index 000000000..bb0f89503 --- /dev/null +++ b/tests/functional/forline.bas @@ -0,0 +1,2 @@ + +FOR i = 1 TO 10 PRINT "HOLA" NEXT diff --git a/tests/functional/forsplitted.asm b/tests/functional/forsplitted.asm new file mode 100644 index 000000000..b4672f6b4 --- /dev/null +++ b/tests/functional/forsplitted.asm @@ -0,0 +1,73 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei +__LABEL__30: + ld a, 1 + ld (_i), a + jp __LABEL0 +__LABEL3: + ld a, 1 + ld (_m), a + jp __LABEL5 +__LABEL8: +__LABEL__40: + xor a + ld (_M), a +__LABEL9: + ld a, (_m) + inc a + ld (_m), a +__LABEL5: + ld a, 6 + ld hl, (_m - 1) + cp h + jp nc, __LABEL8 +__LABEL7: +__LABEL4: + ld a, (_i) + inc a + ld (_i), a +__LABEL0: + ld a, 8 + ld hl, (_i - 1) + cp h + jp nc, __LABEL3 +__LABEL2: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_i: + DEFB 00 +_m: + DEFB 00 +_M: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/forsplitted.bas b/tests/functional/forsplitted.bas new file mode 100644 index 000000000..8591894c8 --- /dev/null +++ b/tests/functional/forsplitted.bas @@ -0,0 +1,5 @@ + +30 FOR i=1 TO 8: FOR m=1 TO 6 +40 LET M=0: NEXT m: NEXT i + + diff --git a/tests/functional/forsplitted0.asm b/tests/functional/forsplitted0.asm new file mode 100644 index 000000000..cdc57714f --- /dev/null +++ b/tests/functional/forsplitted0.asm @@ -0,0 +1,85 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei +__LABEL__10: +__LABEL__20: + ld a, 1 + ld (_i), a + jp __LABEL0 +__LABEL3: +__LABEL__30: + ld a, (_i) + inc a + ld (_i), a +__LABEL4: + ld a, (_i) + inc a + ld (_i), a +__LABEL0: + ld a, 10 + ld hl, (_i - 1) + call __LTI8 + or a + jp z, __LABEL3 +__LABEL2: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "lti8.asm" + +#line 1 "lei8.asm" + +__LEI8: ; Signed <= comparison for 8bit int + ; A <= H (registers) + PROC + LOCAL checkParity + sub h + jr nz, __LTI + inc a + ret + +__LTI8: ; Test 8 bit values A < H + sub h + +__LTI: ; Generic signed comparison + jp po, checkParity + xor 0x80 +checkParity: + ld a, 0 ; False + ret p + inc a ; True + ret + ENDP +#line 2 "lti8.asm" +#line 39 "forsplitted0.bas" + +ZXBASIC_USER_DATA: +_i: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/forsplitted0.bas b/tests/functional/forsplitted0.bas new file mode 100644 index 000000000..398e28841 --- /dev/null +++ b/tests/functional/forsplitted0.bas @@ -0,0 +1,4 @@ +10 DIM i as Byte +20 FOR i = 1 TO 10 +30 LET i = i + 1: NEXT i + diff --git a/tests/functional/forsplitted1.asm b/tests/functional/forsplitted1.asm new file mode 100644 index 000000000..329cb1ae9 --- /dev/null +++ b/tests/functional/forsplitted1.asm @@ -0,0 +1,71 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld a, 1 + ld (_i), a + jp __LABEL0 +__LABEL3: + ld a, 1 + ld (_m), a + jp __LABEL5 +__LABEL8: + xor a + ld (_M), a +__LABEL9: + ld a, (_m) + inc a + ld (_m), a +__LABEL5: + ld a, 6 + ld hl, (_m - 1) + cp h + jp nc, __LABEL8 +__LABEL7: +__LABEL4: + ld a, (_i) + inc a + ld (_i), a +__LABEL0: + ld a, 8 + ld hl, (_i - 1) + cp h + jp nc, __LABEL3 +__LABEL2: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_i: + DEFB 00 +_m: + DEFB 00 +_M: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/forsplitted1.bas b/tests/functional/forsplitted1.bas new file mode 100644 index 000000000..04e37e65f --- /dev/null +++ b/tests/functional/forsplitted1.bas @@ -0,0 +1,5 @@ + +FOR i=1 TO 8: FOR m=1 TO 6 +LET M=0: NEXT m: NEXT i + + diff --git a/tests/functional/funcif.asm b/tests/functional/funcif.asm new file mode 100644 index 000000000..f2dd569bc --- /dev/null +++ b/tests/functional/funcif.asm @@ -0,0 +1,197 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld a, (_y) + ld de, (_y + 1) + ld bc, (_y + 3) + call __FTOU32REG + ld a, l + push af + ld a, (_x) + ld de, (_x + 1) + ld bc, (_x + 3) + call __FTOU32REG + ld a, l + push af + call _ScanNear + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +_ScanNear: + push ix + ld ix, 0 + add ix, sp + ld hl, 0 + push hl + inc sp + ld a, (ix+5) + dec a + sub 1 + sbc a, a + push af + ld a, (ix+7) + dec a + sub 1 + sbc a, a + ld h, a + pop af + or h + or a + jp z, __LABEL1 + ld (ix-1), 1 +__LABEL1: + ld a, (ix-1) + jp _ScanNear__leave +_ScanNear__leave: + ld sp, ix + pop ix + exx + pop hl + pop bc + ex (sp), hl + exx + ret +#line 1 "ftou32reg.asm" + +#line 1 "neg32.asm" + +__ABS32: + bit 7, d + ret z + +__NEG32: ; Negates DEHL (Two's complement) + ld a, l + cpl + ld l, a + + ld a, h + cpl + ld h, a + + ld a, e + cpl + ld e, a + + ld a, d + cpl + ld d, a + + inc l + ret nz + + inc h + ret nz + + inc de + ret + +#line 2 "ftou32reg.asm" + +__FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + ; Output: DEHL 32 bit number (signed) + PROC + + LOCAL __IS_FLOAT + + or a + jr nz, __IS_FLOAT + ; Here if it is a ZX ROM Integer + + ld h, c + ld l, d + ld a, e ; Takes sign: FF = -, 0 = + + ld de, 0 + inc a + jp z, __NEG32 ; Negates if negative + ret + +__IS_FLOAT: ; Jumps here if it is a true floating point number + ld h, e + push hl ; Stores it for later (Contains Sign in H) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + ;ld a, c ; Get exponent + sub 128 ; Exponent -= 128 + jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + +__FTOU32REG_LOOP: + exx ; Shift C'B' E'D' << 1, output bit stays in Carry + sla d + rl e + rl b + rl c + + exx ; Shift DEHL << 1, inserting the carry on the right + rl l + rl h + rl e + rl d + + djnz __FTOU32REG_LOOP + +__FTOU32REG_END: + pop af ; Take the sign bit + or a ; Sets SGN bit to 1 if negative + jp m, __NEG32 ; Negates DEHL + + ret + + ENDP + + +__FTOU8: ; Converts float in C ED LH to Unsigned byte in A + call __FTOU32REG + ld a, l + ret + +#line 65 "funcif.bas" + +ZXBASIC_USER_DATA: +_x: + DEFB 00, 00, 00, 00, 00 +_y: + DEFB 00, 00, 00, 00, 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/funcif.bas b/tests/functional/funcif.bas new file mode 100644 index 000000000..fdeae2afd --- /dev/null +++ b/tests/functional/funcif.bas @@ -0,0 +1,10 @@ + +function ScanNear(x as ubyte,y as ubyte) as ubyte +'This scans next fields of x,y until figure for king or pawn + dim result as ubyte + if x=1 or y=1 then result=1:end if + return result +end Function + +ScanNear(x, y) + diff --git a/tests/functional/ifelse2.asm b/tests/functional/ifelse2.asm new file mode 100644 index 000000000..500813d1f --- /dev/null +++ b/tests/functional/ifelse2.asm @@ -0,0 +1,92 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld h, 0 + ld a, (_i) + call __LTI8 + or a + jp z, __LABEL0 + ld a, (_i) + inc a + ld (_i), a + jp __LABEL1 +__LABEL0: + ld a, (_i) + dec a + ld (_i), a +__LABEL1: + ld h, 0 + ld a, (_i) + call __LTI8 + or a + jp z, __LABEL2 + ld a, (_i) + inc a + ld (_i), a + jp __LABEL3 +__LABEL2: + ld a, (_i) + dec a + ld (_i), a +__LABEL3: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "lti8.asm" + +#line 1 "lei8.asm" + +__LEI8: ; Signed <= comparison for 8bit int + ; A <= H (registers) + PROC + LOCAL checkParity + sub h + jr nz, __LTI + inc a + ret + +__LTI8: ; Test 8 bit values A < H + sub h + +__LTI: ; Generic signed comparison + jp po, checkParity + xor 0x80 +checkParity: + ld a, 0 ; False + ret p + inc a ; True + ret + ENDP +#line 2 "lti8.asm" +#line 46 "ifelse2.bas" + +ZXBASIC_USER_DATA: +_i: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifelse2.bas b/tests/functional/ifelse2.bas new file mode 100644 index 000000000..37c371328 --- /dev/null +++ b/tests/functional/ifelse2.bas @@ -0,0 +1,5 @@ +DIM i as Byte + +IF i < 0 THEN LET i = i + 1 ELSE i = i - 1 +IF i < 0 THEN LET i = i + 1 ELSE i = i - 1: END IF + diff --git a/tests/functional/ifelse3.asm b/tests/functional/ifelse3.asm new file mode 100644 index 000000000..f7ee16152 --- /dev/null +++ b/tests/functional/ifelse3.asm @@ -0,0 +1,78 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld h, 0 + ld a, (_i) + call __LTI8 + or a + jp z, __LABEL0 + ld a, (_i) + inc a + ld (_i), a + jp __LABEL1 +__LABEL0: + ld a, (_i) + dec a + ld (_i), a +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "lti8.asm" + +#line 1 "lei8.asm" + +__LEI8: ; Signed <= comparison for 8bit int + ; A <= H (registers) + PROC + LOCAL checkParity + sub h + jr nz, __LTI + inc a + ret + +__LTI8: ; Test 8 bit values A < H + sub h + +__LTI: ; Generic signed comparison + jp po, checkParity + xor 0x80 +checkParity: + ld a, 0 ; False + ret p + inc a ; True + ret + ENDP +#line 2 "lti8.asm" +#line 32 "ifelse3.bas" + +ZXBASIC_USER_DATA: +_i: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifelse3.bas b/tests/functional/ifelse3.bas new file mode 100644 index 000000000..ccbe6d4e4 --- /dev/null +++ b/tests/functional/ifelse3.bas @@ -0,0 +1,4 @@ +DIM i as Byte + +IF i < 0 THEN LET i = i + 1 ELSE i = i - 1 + diff --git a/tests/functional/ifelse4.asm b/tests/functional/ifelse4.asm new file mode 100644 index 000000000..1e0fc0a94 --- /dev/null +++ b/tests/functional/ifelse4.asm @@ -0,0 +1,78 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld h, 0 + ld a, (_i) + call __LTI8 + or a + jp z, __LABEL0 + ld a, (_i) + inc a + ld (_i), a + jp __LABEL1 +__LABEL0: + ld a, (_i) + dec a + ld (_i), a +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "lti8.asm" + +#line 1 "lei8.asm" + +__LEI8: ; Signed <= comparison for 8bit int + ; A <= H (registers) + PROC + LOCAL checkParity + sub h + jr nz, __LTI + inc a + ret + +__LTI8: ; Test 8 bit values A < H + sub h + +__LTI: ; Generic signed comparison + jp po, checkParity + xor 0x80 +checkParity: + ld a, 0 ; False + ret p + inc a ; True + ret + ENDP +#line 2 "lti8.asm" +#line 32 "ifelse4.bas" + +ZXBASIC_USER_DATA: +_i: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifelse4.bas b/tests/functional/ifelse4.bas new file mode 100644 index 000000000..465a9741f --- /dev/null +++ b/tests/functional/ifelse4.bas @@ -0,0 +1,8 @@ +DIM i as Byte + +IF i < 0 THEN + LET i = i + 1 +ELSE + i = i - 1 +END IF + diff --git a/tests/functional/ifelse5.asm b/tests/functional/ifelse5.asm new file mode 100644 index 000000000..a92740b9c --- /dev/null +++ b/tests/functional/ifelse5.asm @@ -0,0 +1,87 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld h, 0 + ld a, (_i) + call __LTI8 + or a + jp z, __LABEL0 + ld a, (_i) + inc a + ld (_i), a + jp __LABEL1 +__LABEL0: + ld a, (_i) + dec a + ld (_i), a + ld h, 2 + ld a, (_i) + call __LTI8 + or a + jp z, __LABEL3 + ld a, (_i) + inc a + ld (_i), a +__LABEL3: +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "lti8.asm" + +#line 1 "lei8.asm" + +__LEI8: ; Signed <= comparison for 8bit int + ; A <= H (registers) + PROC + LOCAL checkParity + sub h + jr nz, __LTI + inc a + ret + +__LTI8: ; Test 8 bit values A < H + sub h + +__LTI: ; Generic signed comparison + jp po, checkParity + xor 0x80 +checkParity: + ld a, 0 ; False + ret p + inc a ; True + ret + ENDP +#line 2 "lti8.asm" +#line 41 "ifelse5.bas" + +ZXBASIC_USER_DATA: +_i: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifelse5.bas b/tests/functional/ifelse5.bas new file mode 100644 index 000000000..c867372b6 --- /dev/null +++ b/tests/functional/ifelse5.bas @@ -0,0 +1,4 @@ +DIM i as Byte + +IF i < 0 THEN LET i = i + 1 ELSE i = i - 1: IF i < 2 THEN i = i + 1 + diff --git a/tests/functional/ifemptyelse.asm b/tests/functional/ifemptyelse.asm new file mode 100644 index 000000000..5b6a84841 --- /dev/null +++ b/tests/functional/ifemptyelse.asm @@ -0,0 +1,40 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld a, (_a) + dec a + ld (_a), a + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifemptyelse.bas b/tests/functional/ifemptyelse.bas new file mode 100644 index 000000000..0e020e014 --- /dev/null +++ b/tests/functional/ifemptyelse.bas @@ -0,0 +1,5 @@ + +DIM a as Byte + +IF 0 a = a + 1 ELSE a = a - 1 + diff --git a/tests/functional/ifendif.bas b/tests/functional/ifendif.bas new file mode 100644 index 000000000..7c2e848e5 --- /dev/null +++ b/tests/functional/ifendif.bas @@ -0,0 +1,6 @@ + +DIM a as Byte + +IF a < 0 THEN: a = a + 1 +END IF + diff --git a/tests/functional/iffor.asm b/tests/functional/iffor.asm new file mode 100644 index 000000000..2200bea6c --- /dev/null +++ b/tests/functional/iffor.asm @@ -0,0 +1,85 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld h, 10 + ld a, (_a) + call __LTI8 + or a + jp z, __LABEL1 + ld a, 1 + ld (_a), a + jp __LABEL2 +__LABEL5: +__LABEL6: + ld a, (_a) + inc a + ld (_a), a +__LABEL2: + ld a, 10 + ld hl, (_a - 1) + call __LTI8 + or a + jp z, __LABEL5 +__LABEL4: +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "lti8.asm" + +#line 1 "lei8.asm" + +__LEI8: ; Signed <= comparison for 8bit int + ; A <= H (registers) + PROC + LOCAL checkParity + sub h + jr nz, __LTI + inc a + ret + +__LTI8: ; Test 8 bit values A < H + sub h + +__LTI: ; Generic signed comparison + jp po, checkParity + xor 0x80 +checkParity: + ld a, 0 ; False + ret p + inc a ; True + ret + ENDP +#line 2 "lti8.asm" +#line 39 "iffor.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/iffor.bas b/tests/functional/iffor.bas new file mode 100644 index 000000000..59e21fa96 --- /dev/null +++ b/tests/functional/iffor.bas @@ -0,0 +1,5 @@ + +DIM a as Byte + +IF a < 10 THEN FOR a = 1 TO 10: NEXT a + diff --git a/tests/functional/iffor1.asm b/tests/functional/iffor1.asm new file mode 100644 index 000000000..aa2a3db91 --- /dev/null +++ b/tests/functional/iffor1.asm @@ -0,0 +1,85 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld h, 10 + ld a, (_a) + call __LTI8 + or a + jp z, __LABEL1 + ld a, 1 + ld (_a), a + jp __LABEL2 +__LABEL5: +__LABEL6: + ld a, (_a) + inc a + ld (_a), a +__LABEL2: + ld a, 10 + ld hl, (_a - 1) + call __LTI8 + or a + jp z, __LABEL5 +__LABEL4: +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "lti8.asm" + +#line 1 "lei8.asm" + +__LEI8: ; Signed <= comparison for 8bit int + ; A <= H (registers) + PROC + LOCAL checkParity + sub h + jr nz, __LTI + inc a + ret + +__LTI8: ; Test 8 bit values A < H + sub h + +__LTI: ; Generic signed comparison + jp po, checkParity + xor 0x80 +checkParity: + ld a, 0 ; False + ret p + inc a ; True + ret + ENDP +#line 2 "lti8.asm" +#line 39 "iffor1.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/iffor1.bas b/tests/functional/iffor1.bas new file mode 100644 index 000000000..d6cfb7bef --- /dev/null +++ b/tests/functional/iffor1.bas @@ -0,0 +1,6 @@ + +DIM a as Byte + +IF a < 10 THEN FOR a = 1 TO 10 + NEXT a + diff --git a/tests/functional/iffor2.asm b/tests/functional/iffor2.asm new file mode 100644 index 000000000..d0f5d5c57 --- /dev/null +++ b/tests/functional/iffor2.asm @@ -0,0 +1,107 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld h, 10 + ld a, (_a) + call __LTI8 + or a + jp z, __LABEL1 + ld a, 1 + ld (_a), a + jp __LABEL2 +__LABEL5: + ld a, 1 + ld hl, (_a - 1) + call __LTI8 + or a + jp z, __LABEL8 + ld a, (_a) + inc a + ld (_a), a + jp __LABEL9 +__LABEL12: +__LABEL13: + ld a, (_a) + inc a + ld (_a), a +__LABEL9: + ld a, 10 + ld hl, (_a - 1) + call __LTI8 + or a + jp z, __LABEL12 +__LABEL11: +__LABEL8: +__LABEL6: + ld a, (_a) + inc a + ld (_a), a +__LABEL2: + ld a, 10 + ld hl, (_a - 1) + call __LTI8 + or a + jp z, __LABEL5 +__LABEL4: +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "lti8.asm" + +#line 1 "lei8.asm" + +__LEI8: ; Signed <= comparison for 8bit int + ; A <= H (registers) + PROC + LOCAL checkParity + sub h + jr nz, __LTI + inc a + ret + +__LTI8: ; Test 8 bit values A < H + sub h + +__LTI: ; Generic signed comparison + jp po, checkParity + xor 0x80 +checkParity: + ld a, 0 ; False + ret p + inc a ; True + ret + ENDP +#line 2 "lti8.asm" +#line 61 "iffor2.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/iffor2.bas b/tests/functional/iffor2.bas new file mode 100644 index 000000000..b2b5993b4 --- /dev/null +++ b/tests/functional/iffor2.bas @@ -0,0 +1,10 @@ + +DIM a as Byte + +IF a < 10 THEN FOR a = 1 TO 10 + IF a > 1 THEN + FOR a = a + 1 TO 10 + NEXT + END IF + NEXT a + diff --git a/tests/functional/ififelseelse1.asm b/tests/functional/ififelseelse1.asm new file mode 100644 index 000000000..26835b4b9 --- /dev/null +++ b/tests/functional/ififelseelse1.asm @@ -0,0 +1,98 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei +__LABEL__10: +__LABEL__20: + ld h, 10 + ld a, (_a) + call __LTI8 + or a + jp z, __LABEL0 + ld a, (_a) + inc a + ld (_a), a + ld h, 10 + ld a, (_a) + call __LTI8 + or a + jp z, __LABEL2 + ld a, (_a) + inc a + ld (_a), a + jp __LABEL3 +__LABEL2: + ld a, (_a) + dec a + ld (_a), a +__LABEL3: + jp __LABEL1 +__LABEL0: + ld a, (_a) + dec a + ld (_a), a +__LABEL1: +__LABEL__30: + ld a, (_a) + inc a + ld (_a), a + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "lti8.asm" + +#line 1 "lei8.asm" + +__LEI8: ; Signed <= comparison for 8bit int + ; A <= H (registers) + PROC + LOCAL checkParity + sub h + jr nz, __LTI + inc a + ret + +__LTI8: ; Test 8 bit values A < H + sub h + +__LTI: ; Generic signed comparison + jp po, checkParity + xor 0x80 +checkParity: + ld a, 0 ; False + ret p + inc a ; True + ret + ENDP +#line 2 "lti8.asm" +#line 52 "ififelseelse1.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ififelseelse1.bas b/tests/functional/ififelseelse1.bas new file mode 100644 index 000000000..5863cdee9 --- /dev/null +++ b/tests/functional/ififelseelse1.bas @@ -0,0 +1,4 @@ +10 DIM a as Byte +20 IF a < 10 THEN LET a = a + 1: IF a < 10 THEN LET a = a + 1: ELSE LET a = a - 1 ELSE: LET a = a - 1 +30 LET a = a + 1 + diff --git a/tests/functional/ififelseelse2.asm b/tests/functional/ififelseelse2.asm new file mode 100644 index 000000000..e5802dcd6 --- /dev/null +++ b/tests/functional/ififelseelse2.asm @@ -0,0 +1,98 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei +__LABEL__10: +__LABEL__20: + ld h, 10 + ld a, (_a) + call __LTI8 + or a + jp z, __LABEL0 + ld a, (_a) + inc a + ld (_a), a + ld h, 10 + ld a, (_a) + call __LTI8 + or a + jp z, __LABEL2 + ld a, (_a) + inc a + ld (_a), a + jp __LABEL3 +__LABEL2: + ld a, (_a) + dec a + ld (_a), a +__LABEL3: + jp __LABEL1 +__LABEL0: + ld a, (_a) + dec a + ld (_a), a +__LABEL1: +__LABEL__30: + ld a, (_a) + inc a + ld (_a), a + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "lti8.asm" + +#line 1 "lei8.asm" + +__LEI8: ; Signed <= comparison for 8bit int + ; A <= H (registers) + PROC + LOCAL checkParity + sub h + jr nz, __LTI + inc a + ret + +__LTI8: ; Test 8 bit values A < H + sub h + +__LTI: ; Generic signed comparison + jp po, checkParity + xor 0x80 +checkParity: + ld a, 0 ; False + ret p + inc a ; True + ret + ENDP +#line 2 "lti8.asm" +#line 52 "ififelseelse2.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ififelseelse2.bas b/tests/functional/ififelseelse2.bas new file mode 100644 index 000000000..fd07a9a08 --- /dev/null +++ b/tests/functional/ififelseelse2.bas @@ -0,0 +1,4 @@ +10 DIM a as Byte +20 IF a < 10 THEN LET a = a + 1: IF a < 10 THEN LET a = a + 1 ELSE LET a = a - 1 ELSE LET a = a - 1 +30 LET a = a + 1 + diff --git a/tests/functional/ifline.asm b/tests/functional/ifline.asm new file mode 100644 index 000000000..63478dcf1 --- /dev/null +++ b/tests/functional/ifline.asm @@ -0,0 +1,44 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld a, (_a) + dec a + jp nz, __LABEL1 + ld a, (_a) + inc a + ld (_a), a +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 01h + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifline.bas b/tests/functional/ifline.bas new file mode 100644 index 000000000..4506a3c30 --- /dev/null +++ b/tests/functional/ifline.bas @@ -0,0 +1,5 @@ +DIM a as UByte = 1 +IF a = 1 THEN a = a + 1 + + + diff --git a/tests/functional/ifthenelse.asm b/tests/functional/ifthenelse.asm index 59c4d7294..f8e4da478 100644 --- a/tests/functional/ifthenelse.asm +++ b/tests/functional/ifthenelse.asm @@ -20,9 +20,9 @@ __LABEL__10: ld a, (_a) inc a ld (_a), a +__LABEL__20: jp __LABEL1 __LABEL0: -__LABEL__20: xor a ld (_a), a __LABEL__30: diff --git a/tests/functional/ifthenelseif.asm b/tests/functional/ifthenelseif.asm index b9dde0908..28faf8f6e 100644 --- a/tests/functional/ifthenelseif.asm +++ b/tests/functional/ifthenelseif.asm @@ -20,9 +20,9 @@ __LABEL__10: ld a, (_a) inc a ld (_a), a +__LABEL__20: jp __LABEL1 __LABEL0: -__LABEL__20: xor a ld hl, (_a - 1) call __LTI8 @@ -42,9 +42,9 @@ __LABEL__40: ld a, (_a) inc a ld (_a), a +__LABEL__50: jp __LABEL5 __LABEL4: -__LABEL__50: xor a ld hl, (_a - 1) call __LTI8 diff --git a/tests/functional/ifwhile.asm b/tests/functional/ifwhile.asm new file mode 100644 index 000000000..e517a3533 --- /dev/null +++ b/tests/functional/ifwhile.asm @@ -0,0 +1,81 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld h, 0 + ld a, (_a) + call __LTI8 + or a + jp z, __LABEL1 +__LABEL2: + ld h, 10 + ld a, (_a) + call __LTI8 + or a + jp z, __LABEL3 + ld a, (_a) + inc a + ld (_a), a + jp __LABEL2 +__LABEL3: +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "lti8.asm" + +#line 1 "lei8.asm" + +__LEI8: ; Signed <= comparison for 8bit int + ; A <= H (registers) + PROC + LOCAL checkParity + sub h + jr nz, __LTI + inc a + ret + +__LTI8: ; Test 8 bit values A < H + sub h + +__LTI: ; Generic signed comparison + jp po, checkParity + xor 0x80 +checkParity: + ld a, 0 ; False + ret p + inc a ; True + ret + ENDP +#line 2 "lti8.asm" +#line 35 "ifwhile.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 00h + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifwhile.bas b/tests/functional/ifwhile.bas new file mode 100644 index 000000000..84c8e8247 --- /dev/null +++ b/tests/functional/ifwhile.bas @@ -0,0 +1,6 @@ + +DIM a as Byte = 0 + +IF a < 0 THEN WHILE a < 10: a = a + 1: END WHILE + + diff --git a/tests/functional/ifwhile1.asm b/tests/functional/ifwhile1.asm new file mode 100644 index 000000000..977932817 --- /dev/null +++ b/tests/functional/ifwhile1.asm @@ -0,0 +1,81 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld h, 0 + ld a, (_a) + call __LTI8 + or a + jp z, __LABEL1 +__LABEL2: + ld h, 10 + ld a, (_a) + call __LTI8 + or a + jp z, __LABEL3 + ld a, (_a) + inc a + ld (_a), a + jp __LABEL2 +__LABEL3: +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "lti8.asm" + +#line 1 "lei8.asm" + +__LEI8: ; Signed <= comparison for 8bit int + ; A <= H (registers) + PROC + LOCAL checkParity + sub h + jr nz, __LTI + inc a + ret + +__LTI8: ; Test 8 bit values A < H + sub h + +__LTI: ; Generic signed comparison + jp po, checkParity + xor 0x80 +checkParity: + ld a, 0 ; False + ret p + inc a ; True + ret + ENDP +#line 2 "lti8.asm" +#line 35 "ifwhile1.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 00h + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifwhile1.bas b/tests/functional/ifwhile1.bas new file mode 100644 index 000000000..19a556e15 --- /dev/null +++ b/tests/functional/ifwhile1.bas @@ -0,0 +1,7 @@ + +DIM a as Byte = 0 + +IF a < 0 THEN WHILE a < 10 + a = a + 1: END WHILE + + diff --git a/tests/functional/ifwhilex.asm b/tests/functional/ifwhilex.asm new file mode 100644 index 000000000..7bcc9f17b --- /dev/null +++ b/tests/functional/ifwhilex.asm @@ -0,0 +1,1374 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __PRINT_INIT + ld h, 0 + ld a, (_i) + call __LTI8 + or a + jp z, __LABEL1 +__LABEL2: + ld h, 10 + ld a, (_i) + call __LTI8 + or a + jp z, __LABEL3 + ld a, (_i) + inc a + ld (_i), a + jp __LABEL2 +__LABEL3: + ld a, (_i) + call __PRINTI8 + call PRINT_EOL +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "lti8.asm" + +#line 1 "lei8.asm" + +__LEI8: ; Signed <= comparison for 8bit int + ; A <= H (registers) + PROC + LOCAL checkParity + sub h + jr nz, __LTI + inc a + ret + +__LTI8: ; Test 8 bit values A < H + sub h + +__LTI: ; Generic signed comparison + jp po, checkParity + xor 0x80 +checkParity: + ld a, 0 ; False + ret p + inc a ; True + ret + ENDP +#line 2 "lti8.asm" +#line 38 "ifwhilex.bas" +#line 1 "print.asm" + +; vim:ts=4:sw=4:et: + ; PRINT command routine + ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that + +#line 1 "sposn.asm" + + ; Printing positioning library. + PROC + LOCAL ECHO_E + +__LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. + ld de, (S_POSN) + ld hl, (MAXX) + or a + sbc hl, de + ex de, hl + ret + + +__SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. + ld hl, (MAXX) + or a + sbc hl, de + ld (S_POSN), hl ; saves it again + ret + + + ECHO_E EQU 23682 + MAXX EQU ECHO_E ; Max X position + 1 + MAXY EQU MAXX + 1 ; Max Y position + 1 + + S_POSN EQU 23688 + POSX EQU S_POSN ; Current POS X + POSY EQU S_POSN + 1 ; Current POS Y + + ENDP + +#line 6 "print.asm" +#line 1 "cls.asm" + + ; JUMPS directly to spectrum CLS + ; This routine does not clear lower screen + + ;CLS EQU 0DAFh + + ; Our faster implementation + + + +CLS: + PROC + + LOCAL COORDS + LOCAL __CLS_SCR + LOCAL ATTR_P + LOCAL SCREEN + + ld hl, 0 + ld (COORDS), hl + ld hl, 1821h + ld (S_POSN), hl +__CLS_SCR: + ld hl, SCREEN + ld (hl), 0 + ld d, h + ld e, l + inc de + ld bc, 6144 + ldir + + ; Now clear attributes + + ld a, (ATTR_P) + ld (hl), a + ld bc, 767 + ldir + ret + + COORDS EQU 23677 + SCREEN EQU 16384 ; Default start of the screen (can be changed) + ATTR_P EQU 23693 + ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address + + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines + ; to get the start of the screen + ENDP + +#line 7 "print.asm" +#line 1 "in_screen.asm" + + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 3 "in_screen.asm" + +__IN_SCREEN: + ; Returns NO carry if current coords (D, E) + ; are OUT of the screen limits (MAXX, MAXY) + + PROC + LOCAL __IN_SCREEN_ERR + + ld hl, MAXX + ld a, e + cp (hl) + jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + + ld a, d + inc hl + cp (hl) + ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + ;; ret + ret c ; Return if carry (OK) + +__IN_SCREEN_ERR: +__OUT_OF_SCREEN_ERR: + ; Jumps here if out of screen + ld a, ERROR_OutOfScreen + jp __STOP ; Saves error code and exits + + ENDP +#line 8 "print.asm" +#line 1 "table_jump.asm" + + +JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A + add a, a + +JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE + ld e, a + ld d, 0 + +JUMP_HL_PLUS_DE: ; Does JP (HL + DE) + add hl, de + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl +CALL_HL: + jp (hl) + +#line 9 "print.asm" +#line 1 "ink.asm" + + ; Sets ink color in ATTR_P permanently +; Parameter: Paper color in A register + +#line 1 "const.asm" + + ; Global constants + + P_FLAG EQU 23697 + FLAGS2 EQU 23681 + ATTR_P EQU 23693 ; permanet ATTRIBUTES + ATTR_T EQU 23695 ; temporary ATTRIBUTES + CHARS EQU 23606 ; Pointer to ROM/RAM Charset + UDG EQU 23675 ; Pointer to UDG Charset + MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars + +#line 5 "ink.asm" + +INK: + PROC + LOCAL __SET_INK + LOCAL __SET_INK2 + + ld de, ATTR_P + +__SET_INK: + cp 8 + jr nz, __SET_INK2 + + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + or 7 ; Set bits 0,1,2 to enable transparency + ld (de), a + ret + +__SET_INK2: + ; Another entry. This will set the ink color at location pointer by DE + and 7 ; # Gets color mod 8 + ld b, a ; Saves the color + ld a, (de) + and 0F8h ; Clears previous value + or b + ld (de), a + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + and 0F8h ; Reset bits 0,1,2 sign to disable transparency + ld (de), a ; Store new attr + ret + + ; Sets the INK color passed in A register in the ATTR_T variable +INK_TMP: + ld de, ATTR_T + jp __SET_INK + + ENDP + +#line 10 "print.asm" +#line 1 "paper.asm" + + ; Sets paper color in ATTR_P permanently +; Parameter: Paper color in A register + + + +PAPER: + PROC + LOCAL __SET_PAPER + LOCAL __SET_PAPER2 + + ld de, ATTR_P + +__SET_PAPER: + cp 8 + jr nz, __SET_PAPER2 + inc de + ld a, (de) + or 038h + ld (de), a + ret + + ; Another entry. This will set the paper color at location pointer by DE +__SET_PAPER2: + and 7 ; # Remove + rlca + rlca + rlca ; a *= 8 + + ld b, a ; Saves the color + ld a, (de) + and 0C7h ; Clears previous value + or b + ld (de), a + inc de ; Points to MASK_T or MASK_P accordingly + ld a, (de) + and 0C7h ; Resets bits 3,4,5 + ld (de), a + ret + + + ; Sets the PAPER color passed in A register in the ATTR_T variable +PAPER_TMP: + ld de, ATTR_T + jp __SET_PAPER + ENDP + +#line 11 "print.asm" +#line 1 "flash.asm" + + ; Sets flash flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +FLASH: + ld de, ATTR_P +__SET_FLASH: + ; Another entry. This will set the flash flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + ld b, a ; Saves the color + ld a, (de) + and 07Fh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the FLASH flag passed in A register in the ATTR_T variable +FLASH_TMP: + ld de, ATTR_T + jr __SET_FLASH + +#line 12 "print.asm" +#line 1 "bright.asm" + + ; Sets bright flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +BRIGHT: + ld de, ATTR_P + +__SET_BRIGHT: + ; Another entry. This will set the bright flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + rrca + ld b, a ; Saves the color + ld a, (de) + and 0BFh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable +BRIGHT_TMP: + ld de, ATTR_T + jr __SET_BRIGHT + +#line 13 "print.asm" +#line 1 "over.asm" + + ; Sets OVER flag in P_FLAG permanently +; Parameter: OVER flag in bit 0 of A register +#line 1 "copy_attr.asm" + + + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" + + + +COPY_ATTR: + ; Just copies current permanent attribs to temporal attribs + ; and sets print mode + PROC + + LOCAL INVERSE1 + LOCAL __REFRESH_TMP + + INVERSE1 EQU 02Fh + + ld hl, (ATTR_P) + ld (ATTR_T), hl + + ld hl, FLAGS2 + call __REFRESH_TMP + + ld hl, P_FLAG + call __REFRESH_TMP + + +__SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) + + + LOCAL TABLE + LOCAL CONT2 + + rra ; Over bit to carry + ld a, (FLAGS2) + rla ; Over bit in bit 1, Over2 bit in bit 2 + and 3 ; Only bit 0 and 1 (OVER flag) + + ld c, a + ld b, 0 + + ld hl, TABLE + add hl, bc + ld a, (hl) + ld (PRINT_MODE), a + + ld hl, (P_FLAG) + xor a ; NOP -> INVERSE0 + bit 2, l + jr z, CONT2 + ld a, INVERSE1 ; CPL -> INVERSE1 + +CONT2: + ld (INVERSE_MODE), a + ret + +TABLE: + nop ; NORMAL MODE + xor (hl) ; OVER 1 MODE + and (hl) ; OVER 2 MODE + or (hl) ; OVER 3 MODE + +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" + +__REFRESH_TMP: + ld a, (hl) + and 10101010b + ld c, a + rra + or c + ld (hl), a + ret + + ENDP + +#line 4 "over.asm" + + +OVER: + PROC + + ld c, a ; saves it for later + and 2 + ld hl, FLAGS2 + res 1, (HL) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 ; # Convert to 0/1 + add a, a; # Shift left 1 bit for permanent + + ld hl, P_FLAG + res 1, (hl) + or (hl) + ld (hl), a + ret + + ; Sets OVER flag in P_FLAG temporarily +OVER_TMP: + ld c, a ; saves it for later + and 2 ; gets bit 1; clears carry + rra + ld hl, FLAGS2 + res 0, (hl) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 + ld hl, P_FLAG + res 0, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 14 "print.asm" +#line 1 "inverse.asm" + + ; Sets INVERSE flag in P_FLAG permanently +; Parameter: INVERSE flag in bit 0 of A register + + + +INVERSE: + PROC + + and 1 ; # Convert to 0/1 + add a, a; # Shift left 3 bits for permanent + add a, a + add a, a + ld hl, P_FLAG + res 3, (hl) + or (hl) + ld (hl), a + ret + + ; Sets INVERSE flag in P_FLAG temporarily +INVERSE_TMP: + and 1 + add a, a + add a, a; # Shift left 2 bits for temporary + ld hl, P_FLAG + res 2, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 15 "print.asm" +#line 1 "bold.asm" + + ; Sets BOLD flag in P_FLAG permanently +; Parameter: BOLD flag in bit 0 of A register + + +BOLD: + PROC + + and 1 + rlca + rlca + rlca + ld hl, FLAGS2 + res 3, (HL) + or (hl) + ld (hl), a + ret + + ; Sets BOLD flag in P_FLAG temporarily +BOLD_TMP: + and 1 + rlca + rlca + ld hl, FLAGS2 + res 2, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 16 "print.asm" +#line 1 "italic.asm" + + ; Sets ITALIC flag in P_FLAG permanently +; Parameter: ITALIC flag in bit 0 of A register + + +ITALIC: + PROC + + and 1 + rrca + rrca + rrca + ld hl, FLAGS2 + res 5, (HL) + or (hl) + ld (hl), a + ret + + ; Sets ITALIC flag in P_FLAG temporarily +ITALIC_TMP: + and 1 + rrca + rrca + rrca + rrca + ld hl, FLAGS2 + res 4, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 17 "print.asm" + +#line 1 "attr.asm" + + ; Attribute routines +; vim:ts=4:et:sw: + + + + + + + +__ATTR_ADDR: + ; calc start address in DE (as (32 * d) + e) + ; Contributed by Santiago Romero at http://www.speccy.org + ld h, 0 ; 7 T-States + ld a, d ; 4 T-States + add a, a ; a * 2 ; 4 T-States + add a, a ; a * 4 ; 4 T-States + ld l, a ; HL = A * 4 ; 4 T-States + + add hl, hl ; HL = A * 8 ; 15 T-States + add hl, hl ; HL = A * 16 ; 15 T-States + add hl, hl ; HL = A * 32 ; 15 T-States + + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) + add hl, de + + ld de, (SCREEN_ADDR) ; Adds the screen address + add hl, de + + ; Return current screen address in HL + ret + + + ; Sets the attribute at a given screen coordinate (D, E). + ; The attribute is taken from the ATTR_T memory variable + ; Used by PRINT routines +SET_ATTR: + + ; Checks for valid coords + call __IN_SCREEN + ret nc + +__SET_ATTR: + ; Internal __FASTCALL__ Entry used by printing routines + PROC + + call __ATTR_ADDR + ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T + + ld a, d + and (hl) + ld c, a ; C = current screen color, masked + + ld a, d + cpl ; Negate mask + and e ; Mask current attributes + or c ; Mix them + ld (hl), a ; Store result in screen + + ret + + ENDP + + +#line 19 "print.asm" + + ; Putting a comment starting with @INIT
+ ; will make the compiler to add a CALL to
+ ; It is useful for initialization routines. + + +__PRINT_INIT: ; To be called before program starts (initializes library) + PROC + + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + + ld hl, 1821h + ld (MAXX), hl ; Sets current maxX and maxY + + xor a + ld (FLAGS2), a + + ret + + +__PRINTCHAR: ; Print character store in accumulator (A register) + ; Modifies H'L', B'C', A'F', D'E', A + + LOCAL PO_GR_1 + + LOCAL __PRCHAR + LOCAL __PRINT_CONT + LOCAL __PRINT_CONT2 + LOCAL __PRINT_JUMP + LOCAL __SRCADDR + LOCAL __PRINT_UDG + LOCAL __PRGRAPH + LOCAL __PRINT_START + + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 + +__PRINT_JUMP: + jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively + +__PRINT_START: + cp ' ' + jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones + + exx ; Switch to alternative registers + ex af, af' ; Saves a value (char to print) for later + + call __LOAD_S_POSN + + ; At this point we have the new coord + ld hl, (SCREEN_ADDR) + + ld a, d + ld c, a ; Saves it for later + + and 0F8h ; Masks 3 lower bit ; zy + ld d, a + + ld a, c ; Recovers it + and 07h ; MOD 7 ; y1 + rrca + rrca + rrca + + or e + ld e, a + add hl, de ; HL = Screen address + DE + ex de, hl ; DE = Screen address + + ex af, af' + + cp 80h ; Is it an UDG or a ? + jp c, __SRCADDR + + cp 90h + jp nc, __PRINT_UDG + + ; Print a 8 bit pattern (80h to 8Fh) + + ld b, a + call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 + ld hl, MEM0 + jp __PRGRAPH + + PO_GR_1 EQU 0B38h + +__PRINT_UDG: + sub 90h ; Sub ASC code + ld bc, (UDG) + jp __PRGRAPH0 + + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source +__SRCADDR: + ld bc, (CHARS) + +__PRGRAPH0: + add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org + ld l, a + ld h, 0 ; HL = a * 2 (accumulator) + add hl, hl + add hl, hl ; HL = a * 8 + add hl, bc ; HL = CHARS address + +__PRGRAPH: + ex de, hl ; HL = Write Address, DE = CHARS address + bit 2, (iy + $47) + call nz, __BOLD + bit 4, (iy + $47) + call nz, __ITALIC + ld b, 8 ; 8 bytes per char +__PRCHAR: + ld a, (de) ; DE *must* be ALWAYS source, and HL destiny + +PRINT_MODE: ; Which operation is used to write on the screen + ; Set it with: + ; LD A, + ; LD (PRINT_MODE), A + ; + ; Available opertions: + ; NORMAL: 0h --> NOP ; OVER 0 + ; XOR : AEh --> XOR (HL) ; OVER 1 + ; OR : B6h --> OR (HL) ; PUTSPRITE + ; AND : A6h --> AND (HL) ; PUTMASK + nop ; + +INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 + nop ; 2F -> CPL -> INVERSE 1 + + ld (hl), a + + inc de + inc h ; Next line + djnz __PRCHAR + + call __LOAD_S_POSN + push de + call __SET_ATTR + pop de + inc e ; COL = COL + 1 + ld hl, (MAXX) + ld a, e + dec l ; l = MAXX + cp l ; Lower than max? + jp c, __PRINT_CONT; Nothing to do + call __PRINT_EOL1 + exx ; counteracts __PRINT_EOL1 exx + jp __PRINT_CONT2 + +__PRINT_CONT: + call __SAVE_S_POSN + +__PRINT_CONT2: + exx + ret + + ; ------------- SPECIAL CHARS (< 32) ----------------- + +__PRINT_SPECIAL: ; Jumps here if it is a special char + exx + ld hl, __PRINT_TABLE + jp JUMP_HL_PLUS_2A + + +PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence + exx + +__PRINT_0Dh: ; Called WHEN printing CHR$(13) + call __LOAD_S_POSN + +__PRINT_EOL1: ; Another entry called from PRINT when next line required + ld e, 0 + +__PRINT_EOL2: + ld a, d + inc a + +__PRINT_AT1_END: + ld hl, (MAXY) + cp l + jr c, __PRINT_EOL_END ; Carry if (MAXY) < d + xor a + +__PRINT_EOL_END: + ld d, a + +__PRINT_AT2_END: + call __SAVE_S_POSN + exx + ret + +__PRINT_COM: + exx + push hl + push de + push bc + call PRINT_COMMA + pop bc + pop de + pop hl + ret + +__PRINT_TAB: + ld hl, __PRINT_TAB1 + jp __PRINT_SET_STATE + +__PRINT_TAB1: + ld (MEM0), a + ld hl, __PRINT_TAB2 + ld (PRINT_JUMP_STATE), hl + ret + +__PRINT_TAB2: + ld a, (MEM0) ; Load tab code (ignore the current one) + push hl + push de + push bc + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + call PRINT_TAB + pop bc + pop de + pop hl + ret + +__PRINT_NOP: +__PRINT_RESTART: + ld hl, __PRINT_START + jp __PRINT_SET_STATE + +__PRINT_AT: + ld hl, __PRINT_AT1 + +__PRINT_SET_STATE: + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + exx + ret + +__PRINT_AT1: ; Jumps here if waiting for 1st parameter + exx + ld hl, __PRINT_AT2 + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + jp __PRINT_AT1_END + +__PRINT_AT2: + exx + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + ld e, a + ld hl, (MAXX) + cp (hl) + jr c, __PRINT_AT2_END + jr __PRINT_EOL1 + +__PRINT_DEL: + call __LOAD_S_POSN ; Gets current screen position + dec e + ld a, -1 + cp e + jp nz, __PRINT_AT2_END + ld hl, (MAXX) + ld e, l + dec e + dec e + dec d + cp d + jp nz, __PRINT_AT2_END + ld d, h + dec d + jp __PRINT_AT2_END + +__PRINT_INK: + ld hl, __PRINT_INK2 + jp __PRINT_SET_STATE + +__PRINT_INK2: + exx + call INK_TMP + jp __PRINT_RESTART + +__PRINT_PAP: + ld hl, __PRINT_PAP2 + jp __PRINT_SET_STATE + +__PRINT_PAP2: + exx + call PAPER_TMP + jp __PRINT_RESTART + +__PRINT_FLA: + ld hl, __PRINT_FLA2 + jp __PRINT_SET_STATE + +__PRINT_FLA2: + exx + call FLASH_TMP + jp __PRINT_RESTART + +__PRINT_BRI: + ld hl, __PRINT_BRI2 + jp __PRINT_SET_STATE + +__PRINT_BRI2: + exx + call BRIGHT_TMP + jp __PRINT_RESTART + +__PRINT_INV: + ld hl, __PRINT_INV2 + jp __PRINT_SET_STATE + +__PRINT_INV2: + exx + call INVERSE_TMP + jp __PRINT_RESTART + +__PRINT_OVR: + ld hl, __PRINT_OVR2 + jp __PRINT_SET_STATE + +__PRINT_OVR2: + exx + call OVER_TMP + jp __PRINT_RESTART + +__PRINT_BOLD: + ld hl, __PRINT_BOLD2 + jp __PRINT_SET_STATE + +__PRINT_BOLD2: + exx + call BOLD_TMP + jp __PRINT_RESTART + +__PRINT_ITA: + ld hl, __PRINT_ITA2 + jp __PRINT_SET_STATE + +__PRINT_ITA2: + exx + call ITALIC_TMP + jp __PRINT_RESTART + + +__BOLD: + push hl + ld hl, MEM0 + ld b, 8 +__BOLD_LOOP: + ld a, (de) + ld c, a + rlca + or c + ld (hl), a + inc hl + inc de + djnz __BOLD_LOOP + pop hl + ld de, MEM0 + ret + + +__ITALIC: + push hl + ld hl, MEM0 + ex de, hl + ld bc, 8 + ldir + ld hl, MEM0 + srl (hl) + inc hl + srl (hl) + inc hl + srl (hl) + inc hl + inc hl + inc hl + sla (hl) + inc hl + sla (hl) + inc hl + sla (hl) + pop hl + ld de, MEM0 + ret + +PRINT_COMMA: + call __LOAD_S_POSN + ld a, e + and 16 + add a, 16 + +PRINT_TAB: + PROC + LOCAL LOOP, CONTINUE + + inc a + call __LOAD_S_POSN ; e = current row + ld d, a + ld a, e + cp 21h + jr nz, CONTINUE + ld e, -1 +CONTINUE: + ld a, d + inc e + sub e ; A = A - E + and 31 ; + ret z ; Already at position E + ld b, a +LOOP: + ld a, ' ' + call __PRINTCHAR + djnz LOOP + ret + ENDP + +PRINT_AT: ; CHanges cursor to ROW, COL + ; COL in A register + ; ROW in stack + + pop hl ; Ret address + ex (sp), hl ; callee H = ROW + ld l, a + ex de, hl + + call __IN_SCREEN + ret nc ; Return if out of screen + + jp __SAVE_S_POSN + + LOCAL __PRINT_COM + LOCAL __BOLD + LOCAL __BOLD_LOOP + LOCAL __ITALIC + LOCAL __PRINT_EOL1 + LOCAL __PRINT_EOL2 + LOCAL __PRINT_AT1 + LOCAL __PRINT_AT2 + LOCAL __PRINT_AT2_END + LOCAL __PRINT_BOLD + LOCAL __PRINT_BOLD2 + LOCAL __PRINT_ITA + LOCAL __PRINT_ITA2 + LOCAL __PRINT_INK + LOCAL __PRINT_PAP + LOCAL __PRINT_SET_STATE + LOCAL __PRINT_TABLE + LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 + +__PRINT_TABLE: ; Jump table for 0 .. 22 codes + + DW __PRINT_NOP ; 0 + DW __PRINT_NOP ; 1 + DW __PRINT_NOP ; 2 + DW __PRINT_NOP ; 3 + DW __PRINT_NOP ; 4 + DW __PRINT_NOP ; 5 + DW __PRINT_COM ; 6 COMMA + DW __PRINT_NOP ; 7 + DW __PRINT_DEL ; 8 DEL + DW __PRINT_NOP ; 9 + DW __PRINT_NOP ; 10 + DW __PRINT_NOP ; 11 + DW __PRINT_NOP ; 12 + DW __PRINT_0Dh ; 13 + DW __PRINT_BOLD ; 14 + DW __PRINT_ITA ; 15 + DW __PRINT_INK ; 16 + DW __PRINT_PAP ; 17 + DW __PRINT_FLA ; 18 + DW __PRINT_BRI ; 19 + DW __PRINT_INV ; 20 + DW __PRINT_OVR ; 21 + DW __PRINT_AT ; 22 AT + DW __PRINT_TAB ; 23 TAB + + ENDP + + +#line 39 "ifwhilex.bas" +#line 1 "printi8.asm" + +#line 1 "printnum.asm" + + + + +__PRINTU_START: + PROC + + LOCAL __PRINTU_CONT + + ld a, b + or a + jp nz, __PRINTU_CONT + + ld a, '0' + jp __PRINT_DIGIT + + +__PRINTU_CONT: + pop af + push bc + call __PRINT_DIGIT + pop bc + djnz __PRINTU_CONT + ret + + ENDP + + +__PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers + ld a, '-' + jp __PRINT_DIGIT + + __PRINT_DIGIT EQU __PRINTCHAR ; PRINTS the char in A register, and puts its attrs + + +#line 2 "printi8.asm" +#line 1 "div8.asm" + + ; -------------------------------- +__DIVU8: ; 8 bit unsigned integer division + ; Divides (Top of stack, High Byte) / A + pop hl ; -------------------------------- + ex (sp), hl ; CALLEE + +__DIVU8_FAST: ; Does A / H + ld l, h + ld h, a ; At this point do H / L + + ld b, 8 + xor a ; A = 0, Carry Flag = 0 + +__DIV8LOOP: + sla h + rla + cp l + jr c, __DIV8NOSUB + sub l + inc h + +__DIV8NOSUB: + djnz __DIV8LOOP + + ld l, a ; save remainder + ld a, h ; + + ret ; a = Quotient, + + + ; -------------------------------- +__DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A + pop hl ; -------------------------------- + ex (sp), hl + +__DIVI8_FAST: + ld e, a ; store operands for later + ld c, h + + or a ; negative? + jp p, __DIV8A + neg ; Make it positive + +__DIV8A: + ex af, af' + ld a, h + or a + jp p, __DIV8B + neg + ld h, a ; make it positive + +__DIV8B: + ex af, af' + + call __DIVU8_FAST + + ld a, c + xor l ; bit 7 of A = 1 if result is negative + + ld a, h ; Quotient + ret p ; return if positive + + neg + ret + + +__MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) + pop hl + ex (sp), hl ; CALLEE + +__MODU8_FAST: ; __FASTCALL__ entry + call __DIVU8_FAST + ld a, l ; Remainder + + ret ; a = Modulus + + +__MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) + pop hl + ex (sp), hl ; CALLEE + +__MODI8_FAST: ; __FASTCALL__ entry + call __DIVI8_FAST + ld a, l ; remainder + + ret ; a = Modulus + +#line 3 "printi8.asm" + +__PRINTI8: ; Prints an 8 bits number in Accumulator (A) + ; Converts 8 to 32 bits + or a + jp p, __PRINTU8 + + push af + call __PRINT_MINUS + pop af + neg + +__PRINTU8: + PROC + + LOCAL __PRINTU_LOOP + + ld b, 0 ; Counter + +__PRINTU_LOOP: + or a + jp z, __PRINTU_START + + push bc + ld h, 10 + call __DIVU8_FAST ; Divides by 10. D'E'H'L' contains modulo (L' since < 10) + pop bc + + ld a, l + or '0' ; Stores ASCII digit (must be print in reversed order) + push af + ld a, h + inc b + jp __PRINTU_LOOP ; Uses JP in loops + + ENDP + +#line 40 "ifwhilex.bas" + +ZXBASIC_USER_DATA: +_i: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifwhilex.bas b/tests/functional/ifwhilex.bas new file mode 100644 index 000000000..ac9fa24d3 --- /dev/null +++ b/tests/functional/ifwhilex.bas @@ -0,0 +1,7 @@ + +DIM i as Byte + +IF i < 0 THEN WHILE i < 10: + LET i = i + 1 + END WHILE: PRINT i + diff --git a/tests/functional/label_sent.asm b/tests/functional/label_sent.asm new file mode 100644 index 000000000..53ece31ca --- /dev/null +++ b/tests/functional/label_sent.asm @@ -0,0 +1,36 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei +__LABEL__0: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/label_sent.bas b/tests/functional/label_sent.bas new file mode 100644 index 000000000..c76347c85 --- /dev/null +++ b/tests/functional/label_sent.bas @@ -0,0 +1,2 @@ + 0 REM De MicroHOBBY Nº18, pág. 27 :') + diff --git a/tests/functional/label_sent1.asm b/tests/functional/label_sent1.asm new file mode 100644 index 000000000..3f6e557b4 --- /dev/null +++ b/tests/functional/label_sent1.asm @@ -0,0 +1,49 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei +__LABEL__0: +__LABEL__10: + ld a, 1 + call BORDER + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "border.asm" + + ; __FASTCALL__ Routine to change de border + ; Parameter (color) specified in A register + + BORDER EQU 229Bh + + ; Nothing to do! (Directly from the ZX Spectrum ROM) + +#line 22 "label_sent1.bas" + +ZXBASIC_USER_DATA: + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/label_sent1.bas b/tests/functional/label_sent1.bas new file mode 100644 index 000000000..256b5fff9 --- /dev/null +++ b/tests/functional/label_sent1.bas @@ -0,0 +1,3 @@ +0 REM +10 BORDER 1 + diff --git a/tests/functional/label_sent2.asm b/tests/functional/label_sent2.asm new file mode 100644 index 000000000..d44a692bd --- /dev/null +++ b/tests/functional/label_sent2.asm @@ -0,0 +1,157 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei +__LABEL__0: +__LABEL__10: + ld a, 1 + call BORDER + ld a, 1 + call PAPER + call COPY_ATTR + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "border.asm" + + ; __FASTCALL__ Routine to change de border + ; Parameter (color) specified in A register + + BORDER EQU 229Bh + + ; Nothing to do! (Directly from the ZX Spectrum ROM) + +#line 25 "label_sent2.bas" +#line 1 "copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" + +#line 1 "const.asm" + + ; Global constants + + P_FLAG EQU 23697 + FLAGS2 EQU 23681 + ATTR_P EQU 23693 ; permanet ATTRIBUTES + ATTR_T EQU 23695 ; temporary ATTRIBUTES + CHARS EQU 23606 ; Pointer to ROM/RAM Charset + UDG EQU 23675 ; Pointer to UDG Charset + MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars + +#line 6 "copy_attr.asm" + +COPY_ATTR: + ; Just copies current permanent attribs to temporal attribs + ; and sets print mode + PROC + + LOCAL INVERSE1 + LOCAL __REFRESH_TMP + + INVERSE1 EQU 02Fh + + ld hl, (ATTR_P) + ld (ATTR_T), hl + + ld hl, FLAGS2 + call __REFRESH_TMP + + ld hl, P_FLAG + call __REFRESH_TMP + + +__SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) + +#line 63 "/src/zxb/trunk/library-asm/copy_attr.asm" + ret +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" + +__REFRESH_TMP: + ld a, (hl) + and 10101010b + ld c, a + rra + or c + ld (hl), a + ret + + ENDP + +#line 26 "label_sent2.bas" +#line 1 "paper.asm" + + ; Sets paper color in ATTR_P permanently +; Parameter: Paper color in A register + + + +PAPER: + PROC + LOCAL __SET_PAPER + LOCAL __SET_PAPER2 + + ld de, ATTR_P + +__SET_PAPER: + cp 8 + jr nz, __SET_PAPER2 + inc de + ld a, (de) + or 038h + ld (de), a + ret + + ; Another entry. This will set the paper color at location pointer by DE +__SET_PAPER2: + and 7 ; # Remove + rlca + rlca + rlca ; a *= 8 + + ld b, a ; Saves the color + ld a, (de) + and 0C7h ; Clears previous value + or b + ld (de), a + inc de ; Points to MASK_T or MASK_P accordingly + ld a, (de) + and 0C7h ; Resets bits 3,4,5 + ld (de), a + ret + + + ; Sets the PAPER color passed in A register in the ATTR_T variable +PAPER_TMP: + ld de, ATTR_T + jp __SET_PAPER + ENDP + +#line 27 "label_sent2.bas" + +ZXBASIC_USER_DATA: + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/label_sent2.bas b/tests/functional/label_sent2.bas new file mode 100644 index 000000000..201640dd4 --- /dev/null +++ b/tests/functional/label_sent2.bas @@ -0,0 +1,3 @@ +0 REM +10 BORDER 1: PAPER 1 + diff --git a/tests/functional/label_sent3.asm b/tests/functional/label_sent3.asm new file mode 100644 index 000000000..1793698f7 --- /dev/null +++ b/tests/functional/label_sent3.asm @@ -0,0 +1,157 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei +__LABEL__0: +__LABEL__10: + ld a, 1 + call BORDER + ld a, 1 + call PAPER + call COPY_ATTR + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "border.asm" + + ; __FASTCALL__ Routine to change de border + ; Parameter (color) specified in A register + + BORDER EQU 229Bh + + ; Nothing to do! (Directly from the ZX Spectrum ROM) + +#line 25 "label_sent3.bas" +#line 1 "copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" + +#line 1 "const.asm" + + ; Global constants + + P_FLAG EQU 23697 + FLAGS2 EQU 23681 + ATTR_P EQU 23693 ; permanet ATTRIBUTES + ATTR_T EQU 23695 ; temporary ATTRIBUTES + CHARS EQU 23606 ; Pointer to ROM/RAM Charset + UDG EQU 23675 ; Pointer to UDG Charset + MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars + +#line 6 "copy_attr.asm" + +COPY_ATTR: + ; Just copies current permanent attribs to temporal attribs + ; and sets print mode + PROC + + LOCAL INVERSE1 + LOCAL __REFRESH_TMP + + INVERSE1 EQU 02Fh + + ld hl, (ATTR_P) + ld (ATTR_T), hl + + ld hl, FLAGS2 + call __REFRESH_TMP + + ld hl, P_FLAG + call __REFRESH_TMP + + +__SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) + +#line 63 "/src/zxb/trunk/library-asm/copy_attr.asm" + ret +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" + +__REFRESH_TMP: + ld a, (hl) + and 10101010b + ld c, a + rra + or c + ld (hl), a + ret + + ENDP + +#line 26 "label_sent3.bas" +#line 1 "paper.asm" + + ; Sets paper color in ATTR_P permanently +; Parameter: Paper color in A register + + + +PAPER: + PROC + LOCAL __SET_PAPER + LOCAL __SET_PAPER2 + + ld de, ATTR_P + +__SET_PAPER: + cp 8 + jr nz, __SET_PAPER2 + inc de + ld a, (de) + or 038h + ld (de), a + ret + + ; Another entry. This will set the paper color at location pointer by DE +__SET_PAPER2: + and 7 ; # Remove + rlca + rlca + rlca ; a *= 8 + + ld b, a ; Saves the color + ld a, (de) + and 0C7h ; Clears previous value + or b + ld (de), a + inc de ; Points to MASK_T or MASK_P accordingly + ld a, (de) + and 0C7h ; Resets bits 3,4,5 + ld (de), a + ret + + + ; Sets the PAPER color passed in A register in the ATTR_T variable +PAPER_TMP: + ld de, ATTR_T + jp __SET_PAPER + ENDP + +#line 27 "label_sent3.bas" + +ZXBASIC_USER_DATA: + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/label_sent3.bas b/tests/functional/label_sent3.bas new file mode 100644 index 000000000..7ec6c78f7 --- /dev/null +++ b/tests/functional/label_sent3.bas @@ -0,0 +1,3 @@ +0 REM +10 BORDER 1: PAPER 1: + diff --git a/tests/functional/label_sent4.asm b/tests/functional/label_sent4.asm new file mode 100644 index 000000000..022387cbb --- /dev/null +++ b/tests/functional/label_sent4.asm @@ -0,0 +1,157 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei +__LABEL__0: +__LABEL__10: + ld a, 1 + call BORDER + ld a, 1 + call PAPER + call COPY_ATTR + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "border.asm" + + ; __FASTCALL__ Routine to change de border + ; Parameter (color) specified in A register + + BORDER EQU 229Bh + + ; Nothing to do! (Directly from the ZX Spectrum ROM) + +#line 25 "label_sent4.bas" +#line 1 "copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" + +#line 1 "const.asm" + + ; Global constants + + P_FLAG EQU 23697 + FLAGS2 EQU 23681 + ATTR_P EQU 23693 ; permanet ATTRIBUTES + ATTR_T EQU 23695 ; temporary ATTRIBUTES + CHARS EQU 23606 ; Pointer to ROM/RAM Charset + UDG EQU 23675 ; Pointer to UDG Charset + MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars + +#line 6 "copy_attr.asm" + +COPY_ATTR: + ; Just copies current permanent attribs to temporal attribs + ; and sets print mode + PROC + + LOCAL INVERSE1 + LOCAL __REFRESH_TMP + + INVERSE1 EQU 02Fh + + ld hl, (ATTR_P) + ld (ATTR_T), hl + + ld hl, FLAGS2 + call __REFRESH_TMP + + ld hl, P_FLAG + call __REFRESH_TMP + + +__SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) + +#line 63 "/src/zxb/trunk/library-asm/copy_attr.asm" + ret +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" + +__REFRESH_TMP: + ld a, (hl) + and 10101010b + ld c, a + rra + or c + ld (hl), a + ret + + ENDP + +#line 26 "label_sent4.bas" +#line 1 "paper.asm" + + ; Sets paper color in ATTR_P permanently +; Parameter: Paper color in A register + + + +PAPER: + PROC + LOCAL __SET_PAPER + LOCAL __SET_PAPER2 + + ld de, ATTR_P + +__SET_PAPER: + cp 8 + jr nz, __SET_PAPER2 + inc de + ld a, (de) + or 038h + ld (de), a + ret + + ; Another entry. This will set the paper color at location pointer by DE +__SET_PAPER2: + and 7 ; # Remove + rlca + rlca + rlca ; a *= 8 + + ld b, a ; Saves the color + ld a, (de) + and 0C7h ; Clears previous value + or b + ld (de), a + inc de ; Points to MASK_T or MASK_P accordingly + ld a, (de) + and 0C7h ; Resets bits 3,4,5 + ld (de), a + ret + + + ; Sets the PAPER color passed in A register in the ATTR_T variable +PAPER_TMP: + ld de, ATTR_T + jp __SET_PAPER + ENDP + +#line 27 "label_sent4.bas" + +ZXBASIC_USER_DATA: + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/label_sent4.bas b/tests/functional/label_sent4.bas new file mode 100644 index 000000000..67cfae530 --- /dev/null +++ b/tests/functional/label_sent4.bas @@ -0,0 +1,3 @@ +0 REM +10 :BORDER 1: PAPER 1 + diff --git a/tests/functional/label_sent5.asm b/tests/functional/label_sent5.asm new file mode 100644 index 000000000..474f9b417 --- /dev/null +++ b/tests/functional/label_sent5.asm @@ -0,0 +1,157 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei +__LABEL__0: +__LABEL__10: + ld a, 1 + call BORDER + ld a, 1 + call PAPER + call COPY_ATTR + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "border.asm" + + ; __FASTCALL__ Routine to change de border + ; Parameter (color) specified in A register + + BORDER EQU 229Bh + + ; Nothing to do! (Directly from the ZX Spectrum ROM) + +#line 25 "label_sent5.bas" +#line 1 "copy_attr.asm" + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" + +#line 1 "const.asm" + + ; Global constants + + P_FLAG EQU 23697 + FLAGS2 EQU 23681 + ATTR_P EQU 23693 ; permanet ATTRIBUTES + ATTR_T EQU 23695 ; temporary ATTRIBUTES + CHARS EQU 23606 ; Pointer to ROM/RAM Charset + UDG EQU 23675 ; Pointer to UDG Charset + MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars + +#line 6 "copy_attr.asm" + +COPY_ATTR: + ; Just copies current permanent attribs to temporal attribs + ; and sets print mode + PROC + + LOCAL INVERSE1 + LOCAL __REFRESH_TMP + + INVERSE1 EQU 02Fh + + ld hl, (ATTR_P) + ld (ATTR_T), hl + + ld hl, FLAGS2 + call __REFRESH_TMP + + ld hl, P_FLAG + call __REFRESH_TMP + + +__SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) + +#line 63 "/src/zxb/trunk/library-asm/copy_attr.asm" + ret +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" + +__REFRESH_TMP: + ld a, (hl) + and 10101010b + ld c, a + rra + or c + ld (hl), a + ret + + ENDP + +#line 26 "label_sent5.bas" +#line 1 "paper.asm" + + ; Sets paper color in ATTR_P permanently +; Parameter: Paper color in A register + + + +PAPER: + PROC + LOCAL __SET_PAPER + LOCAL __SET_PAPER2 + + ld de, ATTR_P + +__SET_PAPER: + cp 8 + jr nz, __SET_PAPER2 + inc de + ld a, (de) + or 038h + ld (de), a + ret + + ; Another entry. This will set the paper color at location pointer by DE +__SET_PAPER2: + and 7 ; # Remove + rlca + rlca + rlca ; a *= 8 + + ld b, a ; Saves the color + ld a, (de) + and 0C7h ; Clears previous value + or b + ld (de), a + inc de ; Points to MASK_T or MASK_P accordingly + ld a, (de) + and 0C7h ; Resets bits 3,4,5 + ld (de), a + ret + + + ; Sets the PAPER color passed in A register in the ATTR_T variable +PAPER_TMP: + ld de, ATTR_T + jp __SET_PAPER + ENDP + +#line 27 "label_sent5.bas" + +ZXBASIC_USER_DATA: + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/label_sent5.bas b/tests/functional/label_sent5.bas new file mode 100644 index 000000000..e7a7651b9 --- /dev/null +++ b/tests/functional/label_sent5.bas @@ -0,0 +1,3 @@ +0 REM +10 :BORDER 1: PAPER 1: + diff --git a/tests/functional/labeldecl.asm b/tests/functional/labeldecl.asm new file mode 100644 index 000000000..a21ec6f74 --- /dev/null +++ b/tests/functional/labeldecl.asm @@ -0,0 +1,43 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei +__LABEL__10: +__LABEL__20: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 +_b: + DEFB 00 +_c: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/labeldecl.bas b/tests/functional/labeldecl.bas new file mode 100644 index 000000000..fda6d4718 --- /dev/null +++ b/tests/functional/labeldecl.bas @@ -0,0 +1,5 @@ + + +10 DIM a as Byte +20 DIM b as Byte : DIM c as Byte + diff --git a/tests/functional/labelsent.asm b/tests/functional/labelsent.asm new file mode 100644 index 000000000..4b7bc942e --- /dev/null +++ b/tests/functional/labelsent.asm @@ -0,0 +1,189 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei +__LABEL__10: + ld hl, _a + 4 + call __FP_PUSH_REV + ld a, 081h + ld de, 00000h + ld bc, 00000h + call __ADDF + ld hl, _a + call __STOREF + ld hl, _b + 4 + call __FP_PUSH_REV + ld a, 081h + ld de, 00000h + ld bc, 00000h + call __ADDF + ld hl, _b + call __STOREF + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "addf.asm" + +#line 1 "stackf.asm" + + ; ------------------------------------------------------------- + ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC + ; ------------------------------------------------------------- + + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) + __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) + +__FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) + ; Second argument to push into the stack calculator is popped out of the stack + ; Since the caller routine also receives the parameters into the top of the stack + ; four bytes must be removed from SP before pop them out + + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK + exx + pop hl ; Caller-Caller return addr + exx + pop hl ; Caller return addr + + pop af + pop de + pop bc + + push hl ; Caller return addr + exx + push hl ; Caller-Caller return addr + exx + + jp __FPSTACK_PUSH + + +__FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK + ; This format is specified in the ZX 48K Manual + ; You can push a 16 bit signed integer as + ; 0 SS LL HH 0, being SS the sign and LL HH the low + ; and High byte respectively + ld a, h + rla ; sign to Carry + sbc a, a ; 0 if positive, FF if negative + ld e, a + ld d, l + ld c, h + xor a + ld b, a + jp __FPSTACK_PUSH +#line 2 "addf.asm" + + ; ------------------------------------------------------------- + ; Floating point library using the FP ROM Calculator (ZX 48K) + ; All of them uses A EDCB registers as 1st paramter. + ; For binary operators, the 2n operator must be pushed into the + ; stack, in the order AF DE BC (F not used). + ; + ; Uses CALLEE convention + ; ------------------------------------------------------------- + +__ADDF: ; Addition + call __FPSTACK_PUSH2 + + ; ------------- ROM ADD + rst 28h + defb 0fh ; ADD + defb 38h; ; END CALC + + jp __FPSTACK_POP + +#line 35 "labelsent.bas" +#line 1 "pushf.asm" + + + ; Routine to push Float pointed by HL + ; Into the stack. Notice that the hl points to the last + ; byte of the FP number. + ; Uses H'L' B'C' and D'E' to preserve ABCDEHL registers + +__FP_PUSH_REV: + push hl + exx + pop hl + pop bc ; Return Address + ld d, (hl) + dec hl + ld e, (hl) + dec hl + push de + ld d, (hl) + dec hl + ld e, (hl) + dec hl + push de + ld d, (hl) + push de + push bc ; Return Address + exx + ret + + +#line 36 "labelsent.bas" +#line 1 "storef.asm" + +__PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) + push de + ex de, hl ; DE <- HL + push ix + pop hl ; HL <- IX + add hl, de ; HL <- IX + HL + pop de + +__ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register + ex af, af' + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex af, af' + +__STOREF: ; Stores the given FP number in A EDCB at address HL + ld (hl), a + inc hl + ld (hl), e + inc hl + ld (hl), d + inc hl + ld (hl), c + inc hl + ld (hl), b + ret + +#line 37 "labelsent.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 00, 00, 00, 00, 00 +_b: + DEFB 00, 00, 00, 00, 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/labelsent.bas b/tests/functional/labelsent.bas new file mode 100644 index 000000000..9583ac06c --- /dev/null +++ b/tests/functional/labelsent.bas @@ -0,0 +1,4 @@ + + +10 LET a = a + 1: LET b = b + 1 + diff --git a/tests/functional/whileempty.bas b/tests/functional/whileempty.bas new file mode 100644 index 000000000..13dddf25a --- /dev/null +++ b/tests/functional/whileempty.bas @@ -0,0 +1,3 @@ +DIM i as Byte +WHILE i < 5 END WHILE + diff --git a/tests/functional/whileempty1.asm b/tests/functional/whileempty1.asm new file mode 100644 index 000000000..0d985726a --- /dev/null +++ b/tests/functional/whileempty1.asm @@ -0,0 +1,71 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei +__LABEL0: + ld h, 5 + ld a, (_i) + call __LTI8 + or a + jp nz, __LABEL0 +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "lti8.asm" + +#line 1 "lei8.asm" + +__LEI8: ; Signed <= comparison for 8bit int + ; A <= H (registers) + PROC + LOCAL checkParity + sub h + jr nz, __LTI + inc a + ret + +__LTI8: ; Test 8 bit values A < H + sub h + +__LTI: ; Generic signed comparison + jp po, checkParity + xor 0x80 +checkParity: + ld a, 0 ; False + ret p + inc a ; True + ret + ENDP +#line 2 "lti8.asm" +#line 25 "whileempty1.bas" + +ZXBASIC_USER_DATA: +_i: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/whileempty1.bas b/tests/functional/whileempty1.bas new file mode 100644 index 000000000..eb345f0bd --- /dev/null +++ b/tests/functional/whileempty1.bas @@ -0,0 +1,4 @@ +DIM i as Byte +WHILE i < 5 +END WHILE + diff --git a/tests/functional/whilesplitted.asm b/tests/functional/whilesplitted.asm new file mode 100644 index 000000000..2a6d45bfb --- /dev/null +++ b/tests/functional/whilesplitted.asm @@ -0,0 +1,374 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei +__LABEL0: + ld hl, _i + 4 + call __FP_PUSH_REV + ld a, 081h + ld de, 00000h + ld bc, 00000h + call __EQF + or a + jp z, __LABEL1 + xor a + ld (_M), a + jp __LABEL0 +__LABEL1: +__LABEL2: + ld hl, _i + 4 + call __FP_PUSH_REV + ld a, 081h + ld de, 00000h + ld bc, 00000h + call __EQF + or a + jp z, __LABEL3 + xor a + ld (_M), a + jp __LABEL2 +__LABEL3: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "eqf.asm" + +#line 1 "u32tofreg.asm" + +#line 1 "neg32.asm" + +__ABS32: + bit 7, d + ret z + +__NEG32: ; Negates DEHL (Two's complement) + ld a, l + cpl + ld l, a + + ld a, h + cpl + ld h, a + + ld a, e + cpl + ld e, a + + ld a, d + cpl + ld d, a + + inc l + ret nz + + inc h + ret nz + + inc de + ret + +#line 2 "u32tofreg.asm" +__I8TOFREG: + ld l, a + rlca + sbc a, a ; A = SGN(A) + ld h, a + ld e, a + ld d, a + +__I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) + ; to a Floating Point Number returned in (A ED CB) + + ld a, d + or a ; Test sign + + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __U32TOFREG ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + +__U8TOFREG: + ; Converts an unsigned 8 bit (A) to Floating point + ld l, a + ld h, 0 + ld e, h + ld d, h + +__U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in A ED CB + + PROC + + LOCAL __U32TOFREG_END + + ld a, d + or e + or h + or l + ld b, d + ld c, e ; Returns 00 0000 0000 if ZERO + ret z + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 128 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + +__U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG + exx + ld a, d ; B'C'D'E' == 0 ? + or e + or b + or c + jp z, __U32TOFREG_END ; We are done + + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry + rr c + rr d + rr e + exx + + rr e ; Shift EDCB >> 1, inserting the carry on the left + rr d + rr c + rr b + + inc l ; Increment exponent + jp __U32TOFREG_LOOP + + +__U32TOFREG_END: + exx + ld a, l ; Puts the exponent in a + res 7, e ; Sets the sign bit to 0 (positive) + + ret + ENDP + +#line 2 "eqf.asm" +#line 1 "ftou32reg.asm" + + + +__FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + ; Output: DEHL 32 bit number (signed) + PROC + + LOCAL __IS_FLOAT + + or a + jr nz, __IS_FLOAT + ; Here if it is a ZX ROM Integer + + ld h, c + ld l, d + ld a, e ; Takes sign: FF = -, 0 = + + ld de, 0 + inc a + jp z, __NEG32 ; Negates if negative + ret + +__IS_FLOAT: ; Jumps here if it is a true floating point number + ld h, e + push hl ; Stores it for later (Contains Sign in H) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + ;ld a, c ; Get exponent + sub 128 ; Exponent -= 128 + jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + +__FTOU32REG_LOOP: + exx ; Shift C'B' E'D' << 1, output bit stays in Carry + sla d + rl e + rl b + rl c + + exx ; Shift DEHL << 1, inserting the carry on the right + rl l + rl h + rl e + rl d + + djnz __FTOU32REG_LOOP + +__FTOU32REG_END: + pop af ; Take the sign bit + or a ; Sets SGN bit to 1 if negative + jp m, __NEG32 ; Negates DEHL + + ret + + ENDP + + +__FTOU8: ; Converts float in C ED LH to Unsigned byte in A + call __FTOU32REG + ld a, l + ret + +#line 3 "eqf.asm" +#line 1 "stackf.asm" + + ; ------------------------------------------------------------- + ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC + ; ------------------------------------------------------------- + + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) + __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) + +__FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) + ; Second argument to push into the stack calculator is popped out of the stack + ; Since the caller routine also receives the parameters into the top of the stack + ; four bytes must be removed from SP before pop them out + + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK + exx + pop hl ; Caller-Caller return addr + exx + pop hl ; Caller return addr + + pop af + pop de + pop bc + + push hl ; Caller return addr + exx + push hl ; Caller-Caller return addr + exx + + jp __FPSTACK_PUSH + + +__FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK + ; This format is specified in the ZX 48K Manual + ; You can push a 16 bit signed integer as + ; 0 SS LL HH 0, being SS the sign and LL HH the low + ; and High byte respectively + ld a, h + rla ; sign to Carry + sbc a, a ; 0 if positive, FF if negative + ld e, a + ld d, l + ld c, h + xor a + ld b, a + jp __FPSTACK_PUSH +#line 4 "eqf.asm" + + ; ------------------------------------------------------------- + ; Floating point library using the FP ROM Calculator (ZX 48K) + + ; All of them uses C EDHL registers as 1st paramter. + ; For binary operators, the 2n operator must be pushed into the + ; stack, in the order BC DE HL (B not used). + ; + ; Uses CALLEE convention + ; ------------------------------------------------------------- + + +__EQF: ; A = B + call __FPSTACK_PUSH2 + + ; ------------- ROM NOS-EQL + ld b, 0Eh ; For comparison operators, OP must be in B also + rst 28h + defb 0Eh + defb 38h; ; END CALC + + call __FPSTACK_POP + jp __FTOU8 ; Convert to 8 bits + +#line 44 "whilesplitted.bas" +#line 1 "pushf.asm" + + + ; Routine to push Float pointed by HL + ; Into the stack. Notice that the hl points to the last + ; byte of the FP number. + ; Uses H'L' B'C' and D'E' to preserve ABCDEHL registers + +__FP_PUSH_REV: + push hl + exx + pop hl + pop bc ; Return Address + ld d, (hl) + dec hl + ld e, (hl) + dec hl + push de + ld d, (hl) + dec hl + ld e, (hl) + dec hl + push de + ld d, (hl) + push de + push bc ; Return Address + exx + ret + + +#line 45 "whilesplitted.bas" + +ZXBASIC_USER_DATA: +_i: + DEFB 00, 00, 00, 00, 00 +_M: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/whilesplitted.bas b/tests/functional/whilesplitted.bas new file mode 100644 index 000000000..1d39bb9f7 --- /dev/null +++ b/tests/functional/whilesplitted.bas @@ -0,0 +1,7 @@ + +WHILE i=1: +LET M=0: WEND + +WHILE i=1: +LET M=0: END WHILE + diff --git a/zxblex.py b/zxblex.py index 56ea426ad..b948c537a 100755 --- a/zxblex.py +++ b/zxblex.py @@ -492,7 +492,6 @@ def t_preproc_EQ(t): return t -# tokens regexp. patterns def t_ID(t): r'[a-zA-Z][a-zA-Z0-9]*[$%]?' t.type = reserved.get(t.value.lower(), 'ID') diff --git a/zxbparser.py b/zxbparser.py index 0b637ede7..db66f917e 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -205,7 +205,7 @@ def make_constexpr(lineno, expr): def make_strslice(lineno, s, lower, upper): - """ Wrapper: returns Strlice node + """ Wrapper: returns String Slice node """ return symbols.STRSLICE.make_node(lineno, s, lower, upper) @@ -387,6 +387,7 @@ def make_label(id_, lineno): # Operators precedence # ---------------------------------------------------------------------- precedence = ( + ('nonassoc', 'ID', 'ARRAY_ID'), ('left', 'OR'), ('left', 'AND'), ('left', 'XOR'), @@ -399,6 +400,12 @@ def make_label(id_, lineno): ('left', 'MUL', 'DIV'), ('right', 'UMINUS'), ('right', 'POW'), + ('left', 'RP'), + ('right', 'LP'), + ('right', 'ELSE'), + ('left', 'CO'), + ('left', 'NEWLINE'), + ('right', 'LABEL'), ) @@ -480,25 +487,89 @@ def p_program(p): p[0] = make_block(p[1], p[2]) -def p_program_line_(p): - """ program_line : statement - | var_decl - | preproc_line - | label_line +def p_program_line(p): + """ program_line : preproc_line NEWLINE + | label_line NEWLINE + | statements NEWLINE + | statements_co NEWLINE + | co_statements NEWLINE + | co_statements_co NEWLINE + | NEWLINE + """ + p[0] = make_nop() if len(p) == 2 else p[1] + + +def p_co_statements_co(p): + """ co_statements_co : co_statements CO + | co_statements_co CO + | CO + """ + p[0] = p[1] if len(p) == 3 else None + + +def p_co_statements(p): + """ co_statements : co_statements_co statement + """ + p[0] = make_block(p[1], p[2]) + + +def p_statements_co(p): + """ statements_co : statements CO + | statements_co CO + """ + p[0] = p[1] + + +def p_statements_statement(p): + """ statements : statement + | statements_co statement + """ + if len(p) == 2: + p[0] = make_block(p[1]) + else: + p[0] = make_block(p[1], p[2]) + + +def p_var_decls(p): + """ statement : var_decl """ p[0] = p[1] def p_program_line_label(p): - """ label_line : LABEL statement - | LABEL var_decl + """ label_line : LABEL statements + | LABEL co_statements """ - p[0] = make_block(make_label(p[1], p.lineno(1)), p[2]) + lbl = make_label(p[1], p.lineno(1)) + p[0] = make_block(lbl, p[2]) if len(p) == 3 else lbl + + +def p_label_line_label_line_co(p): + """ label_line : label_line_co + """ + p[0] = p[1] + + +def p_label_line_co(p): + """ label_line_co : LABEL statements_co + | LABEL co_statements_co + | LABEL + """ + lbl = make_label(p[1], p.lineno(1)) + p[0] = make_block(lbl, p[2]) if len(p) == 3 else lbl + + +def p_program_line_co(p): + """ program_co : program %prec CO + | program label_line_co + | program co_statements_co %prec CO + | program statements_co %prec CO + """ + p[0] = p[1] if len(p) == 2 else make_block(p[1], p[2]) def p_var_decl(p): - """ var_decl : DIM idlist typedef NEWLINE - | DIM idlist typedef CO + """ var_decl : DIM idlist typedef """ for vardata in p[2]: SYMBOL_TABLE.declare_variable(vardata[0], vardata[1], p[3]) @@ -507,8 +578,7 @@ def p_var_decl(p): def p_var_decl_at(p): - """ var_decl : DIM idlist typedef AT expr CO - | DIM idlist typedef AT expr NEWLINE + """ var_decl : DIM idlist typedef AT expr """ p[0] = None @@ -549,10 +619,8 @@ def p_var_decl_at(p): def p_var_decl_ini(p): - """ var_decl : DIM idlist typedef EQ expr NEWLINE - | DIM idlist typedef EQ expr CO - | CONST idlist typedef EQ expr NEWLINE - | CONST idlist typedef EQ expr CO + """ var_decl : DIM idlist typedef EQ expr + | CONST idlist typedef EQ expr """ p[0] = None if len(p[2]) != 1: @@ -596,8 +664,7 @@ def p_idlist_idlist_id(p): def p_arr_decl(p): - """ var_decl : var_arr_decl NEWLINE - | var_arr_decl CO + """ var_decl : var_arr_decl """ p[0] = None @@ -742,13 +809,6 @@ def p_const_vector_vector_list(p): p[0] = p[1] + [p[3]] -def p_empty_statement(p): - """ statement : NEWLINE - | CO - """ - p[0] = None - - def p_staement_func_decl(p): """ statement : function_declaration """ @@ -756,138 +816,119 @@ def p_staement_func_decl(p): def p_statement_border(p): - """ statement : BORDER expr NEWLINE - | BORDER expr CO + """ statement : BORDER expr """ p[0] = make_sentence('BORDER', - make_typecast(TYPE.ubyte, p[2], p.lineno(3))) + make_typecast(TYPE.ubyte, p[2], p.lineno(1))) def p_statement_plot(p): - """ statement : PLOT expr COMMA expr NEWLINE - | PLOT expr COMMA expr CO + """ statement : PLOT expr COMMA expr """ p[0] = make_sentence('PLOT', make_typecast(TYPE.ubyte, p[2], p.lineno(3)), - make_typecast(TYPE.ubyte, p[4], p.lineno(5))) + make_typecast(TYPE.ubyte, p[4], p.lineno(3))) def p_statement_plot_attr(p): - """ statement : PLOT attr_list expr COMMA expr NEWLINE - | PLOT attr_list expr COMMA expr CO + """ statement : PLOT attr_list expr COMMA expr """ p[0] = make_sentence('PLOT', make_typecast(TYPE.ubyte, p[3], p.lineno(4)), - make_typecast(TYPE.ubyte, p[5], p.lineno(6)), p[2]) + make_typecast(TYPE.ubyte, p[5], p.lineno(4)), p[2]) def p_statement_draw3(p): - """ statement : DRAW expr COMMA expr COMMA expr NEWLINE - | DRAW expr COMMA expr COMMA expr CO + """ statement : DRAW expr COMMA expr COMMA expr """ p[0] = make_sentence('DRAW3', make_typecast(TYPE.integer, p[2], p.lineno(3)), make_typecast(TYPE.integer, p[4], p.lineno(5)), - make_typecast(TYPE.float_, p[6], p.lineno(7))) + make_typecast(TYPE.float_, p[6], p.lineno(5))) def p_statement_draw3_attr(p): - """ statement : DRAW attr_list expr COMMA expr COMMA expr NEWLINE - | DRAW attr_list expr COMMA expr COMMA expr CO + """ statement : DRAW attr_list expr COMMA expr COMMA expr """ p[0] = make_sentence('DRAW3', make_typecast(TYPE.integer, p[3], p.lineno(4)), make_typecast(TYPE.integer, p[5], p.lineno(6)), - make_typecast(TYPE.float_, p[7], p.lineno(8)), p[2]) + make_typecast(TYPE.float_, p[7], p.lineno(6)), p[2]) def p_statement_draw(p): - """ statement : DRAW expr COMMA expr NEWLINE - | DRAW expr COMMA expr CO + """ statement : DRAW expr COMMA expr """ p[0] = make_sentence('DRAW', make_typecast(TYPE.integer, p[2], p.lineno(3)), - make_typecast(TYPE.integer, p[4], p.lineno(5))) + make_typecast(TYPE.integer, p[4], p.lineno(3))) def p_statement_draw_attr(p): - """ statement : DRAW attr_list expr COMMA expr NEWLINE - | DRAW attr_list expr COMMA expr CO + """ statement : DRAW attr_list expr COMMA expr """ p[0] = make_sentence('DRAW', make_typecast(TYPE.integer, p[3], p.lineno(4)), - make_typecast(TYPE.integer, p[5], p.lineno(6)), p[2]) + make_typecast(TYPE.integer, p[5], p.lineno(4)), p[2]) def p_statement_circle(p): - """ statement : CIRCLE expr COMMA expr COMMA expr NEWLINE - | CIRCLE expr COMMA expr COMMA expr CO + """ statement : CIRCLE expr COMMA expr COMMA expr """ p[0] = make_sentence('CIRCLE', make_typecast(TYPE.byte_, p[2], p.lineno(3)), make_typecast(TYPE.byte_, p[4], p.lineno(5)), - make_typecast(TYPE.byte_, p[6], p.lineno(7))) + make_typecast(TYPE.byte_, p[6], p.lineno(5))) def p_statement_circle_attr(p): - """ statement : CIRCLE attr_list expr COMMA expr COMMA expr NEWLINE - | CIRCLE attr_list expr COMMA expr COMMA expr CO + """ statement : CIRCLE attr_list expr COMMA expr COMMA expr """ p[0] = make_sentence('CIRCLE', make_typecast(TYPE.byte_, p[3], p.lineno(4)), make_typecast(TYPE.byte_, p[5], p.lineno(6)), - make_typecast(TYPE.byte_, p[7], p.lineno(8)), p[2]) + make_typecast(TYPE.byte_, p[7], p.lineno(6)), p[2]) def p_statement_cls(p): - """ statement : CLS NEWLINE - | CLS CO + """ statement : CLS """ p[0] = make_sentence('CLS') def p_statement_asm(p): - """ statement : ASM NEWLINE - | ASM CO + """ statement : ASM """ p[0] = make_asm_sentence(p[1], p.lineno(1)) def p_statement_randomize(p): - """ statement : RANDOMIZE NEWLINE - | RANDOMIZE CO + """ statement : RANDOMIZE """ - p[0] = make_sentence('RANDOMIZE', - make_number(0, lineno=p.lineno(1), type_=TYPE.ulong)) + p[0] = make_sentence('RANDOMIZE', make_number(0, lineno=p.lineno(1), type_=TYPE.ulong)) def p_statement_randomize_expr(p): - """ statement : RANDOMIZE expr NEWLINE - | RANDOMIZE expr CO + """ statement : RANDOMIZE expr """ - p[0] = make_sentence('RANDOMIZE', - make_typecast(TYPE.ulong, p[2], p.lineno(1))) + p[0] = make_sentence('RANDOMIZE', make_typecast(TYPE.ulong, p[2], p.lineno(1))) def p_statement_beep(p): - """ statement : BEEP expr COMMA expr NEWLINE - | BEEP expr COMMA expr CO + """ statement : BEEP expr COMMA expr """ p[0] = make_sentence('BEEP', make_typecast(TYPE.float_, p[2], p.lineno(1)), make_typecast(TYPE.float_, p[4], p.lineno(3))) def p_statement_call(p): - """ statement : ID arg_list NEWLINE - | ID arg_list CO - | ID arguments NEWLINE - | ID arguments CO - | ID NEWLINE - | ID CO + """ statement : ID arg_list + | ID arguments + | ID """ - if p[2] is None: + if len(p) > 2 and p[2] is None: p[0] = None - elif len(p) == 3: + elif len(p) == 2: entry = SYMBOL_TABLE.get_entry(p[1]) if not entry or entry.class_ in (CLASS.label, CLASS.unknown): p[0] = make_label(p[1], p.lineno(1)) @@ -898,24 +939,23 @@ def p_statement_call(p): def p_assignment(p): - """ statement : lexpr expr CO - | lexpr expr NEWLINE + """ statement : lexpr expr """ global LET_ASSIGNMENT LET_ASSIGNMENT = False # Mark we're no longer using LET p[0] = None q = p[1:] - i = 3 + i = 1 if q[1] is None: return if isinstance(q[1], symbols.VAR) and q[1].class_ == CLASS.unknown: - q[1] = SYMBOL_TABLE.access_var(q[1].name, p.lineno(3)) + q[1] = SYMBOL_TABLE.access_var(q[1].name, p.lineno(i)) q1class_ = q[1].class_ if isinstance(q[1], symbols.VAR) else CLASS.unknown - variable = SYMBOL_TABLE.access_id(q[0], p.lineno(3), default_type=q[1].type_, default_class=q1class_) + variable = SYMBOL_TABLE.access_id(q[0], p.lineno(i), default_type=q[1].type_, default_class=q1class_) if variable is None: return # HINT: This only happens if variable was not declared with DIM and --strict flag is in use @@ -957,7 +997,7 @@ def p_assignment(p): p[0] = make_sentence('ARRAYCOPY', variable, q[1]) return - expr = make_typecast(variable.type_, q[1], p.lineno(3)) + expr = make_typecast(variable.type_, q[1], p.lineno(i)) p[0] = make_sentence('LET', variable, expr) @@ -982,10 +1022,8 @@ def p_lexpr(p): def p_arr_assignment(p): - """ statement : ARRAY_ID arg_list EQ expr CO - | ARRAY_ID arg_list EQ expr NEWLINE - | LET ARRAY_ID arg_list EQ expr CO - | LET ARRAY_ID arg_list EQ expr NEWLINE + """ statement : ARRAY_ID arg_list EQ expr + | LET ARRAY_ID arg_list EQ expr """ q = p[1:] i = 2 @@ -1011,10 +1049,8 @@ def p_arr_assignment(p): def p_substr_assignment(p): - """ statement : ID arg_list EQ expr CO - | ID arg_list EQ expr NEWLINE - | LET ID arg_list EQ expr CO - | LET ID arg_list EQ expr NEWLINE + """ statement : ID arg_list EQ expr + | LET ID arg_list EQ expr """ q = p[1:] i = 2 @@ -1066,10 +1102,8 @@ def p_substr_assignment(p): def p_str_assign(p): - """ statement : ID substr EQ expr CO - | ID substr EQ expr NEWLINE - | LET ID substr EQ expr CO - | LET ID substr EQ expr NEWLINE + """ statement : ID substr EQ expr + | LET ID substr EQ expr """ if p[1].upper() != 'LET': q = p[1] @@ -1098,10 +1132,8 @@ def p_str_assign(p): def p_goto(p): - """ statement : goto NUMBER CO - | goto NUMBER NEWLINE - | goto ID CO - | goto ID NEWLINE + """ statement : goto NUMBER + | goto ID """ entry = check_and_make_label(p[2], p.lineno(2)) if entry is not None: @@ -1125,39 +1157,105 @@ def p_endif(p): """ endif : END IF | LABEL END IF """ - if p[1] == 'END': - p[0] = make_nop() - else: - p[0] = make_label(p[1], p.lineno(1)) + p[0] = make_nop() if p[1] == 'END' else make_label(p[1], p.lineno(1)) def p_if_sentence(p): - """ statement : IF expr then program endif CO - | IF expr then program endif NEWLINE + """ statement : if_then_part NEWLINE program_co endif + | if_then_part NEWLINE endif """ - if is_null(p[4]): - warning(p.lineno(1), 'Useless empty IF ignored') - p[0] = p[5] + cond_ = p[1] + if len(p) == 5: + stat_ = p[3] + endif_ = p[4] + else: + stat_ = make_nop() + endif_ = p[3] + + if is_null(stat_): + api.errmsg.warning_empty_if(p.lineno(2)) + p[0] = endif_ return - if is_number(p[2]): - api.errmsg.warning_condition_is_always(p.lineno(1), bool(p[2].value)) + if is_number(cond_): if OPTIONS.optimization.value > 0: - if not p[2].value: - p[0] = p[5] + if not cond_.value: + p[0] = endif_ + return + else: + p[0] = make_block(stat_, endif_) + return + + p[0] = make_sentence('IF', cond_, make_block(stat_, endif_)) + + +def p_statement_if(p): + """ statement : if_inline %prec RP + """ + p[0] = p[1] + + +def p_statement_if_then_endif(p): + """ statement : if_then_part statements_co endif + | if_then_part co_statements_co endif + """ + cond_ = p[1] + stat_ = p[2] + endif_ = p[3] + + if is_null(stat_): + api.errmsg.warning_empty_if(p.lineno(1)) + p[0] = endif_ + return + + if is_number(cond_): + if OPTIONS.optimization.value > 0: + if not cond_.value: + p[0] = endif_ return else: - p[0] = make_block(p[4], p[5]) + p[0] = make_block(stat_, endif_) return - p[0] = make_sentence('IF', p[2], make_block(p[4], p[5])) + p[0] = make_sentence('IF', cond_, make_block(stat_, endif_)) + + +def p_single_line_if(p): + """ if_inline : if_then_part statements %prec ID + | if_then_part co_statements_co %prec NEWLINE + | if_then_part statements_co %prec NEWLINE + """ + cond_ = p[1] + stat_ = p[2] + # endif_ = make_nop() + + if is_null(stat_): + api.errmsg.warning_empty_if(p.lineno(1)) + # TODO: Optimize this in the visitor since this rule is also use in the ELSE part + # p[0] = endif_ + return + + # TODO: Optimize this in the visitor since this rule is also use in the ELSE part + # if is_number(cond_): + # if OPTIONS.optimization.value > 0: + # if not cond_.value: + # p[0] = endif_ + # return + # else: + # p[0] = stat_ + # return + + p[0] = make_sentence('IF', cond_, stat_) def p_if_elseif(p): - """ statement : IF expr then program elseiflist CO - | IF expr then program elseiflist NEWLINE + """ statement : if_then_part NEWLINE program_co elseiflist + | if_then_part NEWLINE elseiflist """ - if is_null(p[4], p[5]): + cond_ = p[1] + stats_ = p[3] if len(p) == 5 else make_nop() + eliflist = p[4] if len(p) == 5 else p[3] + if is_null(stats_, eliflist): p[0] = make_nop() return @@ -1165,18 +1263,20 @@ def p_if_elseif(p): api.errmsg.warning_condition_is_always(p.lineno(1), bool(p[2].value)) if OPTIONS.optimization.value > 0: if not p[2].value: - p[0] = p[5] + p[0] = eliflist + return + else: + p[0] = stats_ return - if not p[4]: # Empty block? - p[4].appendChild(make_nop()) - - p[0] = make_sentence('IF', p[2], p[4], p[5]) + p[0] = make_sentence('IF', cond_, stats_, eliflist) def p_elseif_list(p): - """ elseiflist : ELSEIF expr then program endif - | LABEL ELSEIF expr then program endif + """ elseiflist : ELSEIF expr then program_co endif + | LABEL ELSEIF expr then program_co endif + | ELSEIF expr then program_co else_part + | LABEL ELSEIF expr then program_co else_part """ if p[1] == 'ELSEIF': p1 = make_nop() # No label @@ -1189,6 +1289,12 @@ def p_elseif_list(p): p4 = p[5] p5 = p[6] + if isinstance(p5, list): # it's an else part + p5 = make_block(*p5) + else: + p4 = make_block(p4, p5) + p5 = None + if is_null(p4): warning(p.lineno(1), 'Useless empty ELSEIF ignored') p[0] = make_block(p1, p5) @@ -1201,12 +1307,12 @@ def p_elseif_list(p): p[0] = make_block(p1, p5) return - p[0] = make_block(p1, make_sentence('IF', p2, make_block(p4, p5))) + p[0] = make_block(p1, make_sentence('IF', p2, p4, p5)) def p_elseif_elseiflist(p): - """ elseiflist : ELSEIF expr then program elseiflist - | LABEL ELSEIF expr then program elseiflist + """ elseiflist : ELSEIF expr then program_co elseiflist + | LABEL ELSEIF expr then program_co elseiflist """ if p[1] == 'ELSEIF': p1 = make_nop() @@ -1232,118 +1338,83 @@ def p_elseif_elseiflist(p): p[0] = make_block(p1, make_sentence('IF', p2, p4, p5)) -def p_else(p): - """ else : ELSE - | LABEL ELSE +def p_else_part_endif(p): + """ else_part_inline : ELSE NEWLINE program_co endif + | ELSE statements_co endif + | ELSE co_statements_co endif """ - if p[1] == 'ELSE': - p[0] = make_nop() - else: - p[0] = make_label(p[1], p.lineno(1)) + p[0] = [p[2], p[3]] if len(p) == 4 else [p[3], p[4]] -def p_if_else(p): - """ statement : IF expr then program else program endif CO - | IF expr then program else program endif NEWLINE +def p_else_part(p): + """ else_part_inline : ELSE statements_co + | ELSE co_statements_co + | ELSE co_statements + | ELSE statements """ - if is_null(p[4], p[6]): - warning(p.lineno(1), 'Useless empty IF ignored') - p[0] = p[7] - return + p[0] = [p[2], make_nop()] - if is_number(p[2]): - api.errmsg.warning_condition_is_always(p.lineno(1), bool(p[2].value)) - if not p[2].value: - p[0] = make_block(p[6], p[7]) - return - else: - p[0] = make_block(p[4], p[7]) - return - if is_null(p[4]): - p[2] = make_unary(p.lineno(1), 'NOT', p[2], lambda x: not x) - p[0] = make_sentence('IF', p[2], make_block(p[5], p[6], p[7])) - - if is_null(p[6]): - p[6] = make_nop() - - p[0] = make_sentence('IF', p[2], p[4], make_block(p[5], p[6], p[7])) +def p_else_part_is_inline(p): + """ else_part : else_part_inline + """ + p[0] = p[1] -def p_if_elseif_else(p): - """ statement : IF expr then program elseif_elselist program endif CO - | IF expr then program elseif_elselist program endif NEWLINE +def p_else_part_label(p): + """ else_part : LABEL ELSE program_co endif + | LABEL ELSE statements_co endif + | LABEL ELSE co_statements_co endif """ - if is_number(p[2]) and p[2].value == 0: # Always false? - api.errmsg.warning_condition_is_always(p.lineno(1)) - if OPTIONS.optimization.value > 0: - if is_null(p[5]): # If no else part, return last parts - p[0] = make_block(p[6], p[7]) - return + lbl = make_label(p[1], p.lineno(1)) + p[0] = [make_block(lbl, p[3]), p[4]] - p[5][1].children[-1].appendChild(make_block(p[6], p[7])) - p[0] = p[5] - return - if is_null(p[5]): # Normal IF/THEN/ELSE - p[0] = make_sentence('IF', p[2], p[4], make_block(p[6], p[7])) - return +def p_if_then_part(p): + """ if_then_part : IF expr then """ + if is_number(p[2]): + api.errmsg.warning_condition_is_always(p.lineno(1), bool(p[2].value)) - p[5][1].children[-1].appendChild(make_block(p[6], p[7])) - p[0] = make_sentence('IF', p[2], p[4], p[5][0]) + p[0] = p[2] -def p_elseif_elselist_else(p): - """ elseif_elselist : ELSEIF expr then program else - | LABEL ELSEIF expr then program else +def p_if_inline(p): + """ statement : if_inline else_part_inline """ - if p[1] == 'ELSEIF': - p1 = make_nop() - p2 = p[2] - p4 = p[4] - p5 = p[5] - else: - p1 = make_label(p[1], p.lineno(1)) - p2 = p[3] - p4 = p[5] - p5 = p[6] - - if is_number(p2): - api.errmsg.warning_condition_is_always(p.lineno(1), bool(p2.value)) - if OPTIONS.optimization.value > 0: - if not p2.value: - p[0] = p1 - return - - # p[6] must be added in the rule above - last = make_block(p1, make_sentence('IF', p2, make_block(p4, p5))) - p[0] = (last, last) + p[1].appendChild(make_block(p[2][0], p[2][1])) + p[0] = p[1] -def p_elseif_elselist(p): - """ elseif_elselist : ELSEIF expr then program elseif_elselist - | LABEL ELSEIF expr then program elseif_elselist +def p_if_else(p): + """ statement : if_then_part NEWLINE program_co else_part """ - if p[1] == 'ELSEIF': - p1 = make_nop() - p2 = p[2] - p4 = p[4] - p5 = p[5] - else: - p1 = make_label(p[1], p.lineno(1)) - p2 = p[3] - p4 = p[5] - p5 = p[6] + cond_ = p[1] + then_ = p[3] + else_ = p[4][0] + endif = p[4][1] - if is_number(p2) and p2.value == 0: - api.errmsg.warning_condition_is_always(p.lineno(1)) - if OPTIONS.optimization.value > 0: - last = p5[1] - p[0] = (make_block(p1, p5[0]), last) + if is_null(then_, else_): + api.errmsg.warning_empty_if(p.lineno(2)) + p[0] = endif + return + + if is_number(cond_): + if not cond_.value: + p[0] = make_block(else_, endif) + return + else: + p[0] = make_block(then_, endif) return - node = make_sentence('IF', p2, p4, p5[0]) - p[0] = (make_block(p1, node), p5[1]) + if is_null(then_): + cond_ = make_unary(p.lineno(1), 'NOT', cond_, lambda x: not x) + p[0] = make_sentence('IF', cond_, make_block(else_, endif)) + return + + if is_null(else_): + else_ = None + + p[0] = make_sentence('IF', cond_, then_, make_block(else_, endif)) def p_then(p): @@ -1353,8 +1424,8 @@ def p_then(p): def p_for_sentence(p): - """ statement : for_start program label_next CO - | for_start program label_next NEWLINE + """ statement : for_start program_co label_next + | for_start co_statements_co label_next """ p[0] = p[1] if is_null(p[0]): @@ -1367,10 +1438,7 @@ def p_next(p): """ label_next : LABEL NEXT | NEXT """ - if p[1] == 'NEXT': - p[0] = make_nop() - else: - p[0] = make_label(p[1], p.lineno(1)) + p[0] = make_nop() if p[1] == 'NEXT' else make_label(p[1], p.lineno(1)) def p_next1(p): @@ -1392,46 +1460,6 @@ def p_next1(p): p[0] = p1 -def p_end(p): - """ statement : END expr CO - | END expr NEWLINE - | END CO - | END NEWLINE - """ - q = p[2] - if not isinstance(q, Symbol): - q = make_number(0, lineno=p.lineno(1)) - p[0] = make_sentence('END', q) - - -def p_error_raise(p): - """ statement : ERROR expr CO - | ERROR expr NEWLINE - """ - q = make_number(1, lineno=p.lineno(3)) - r = make_binary(p.lineno(1), 'MINUS', - make_typecast(TYPE.ubyte, p[2], p.lineno(1)), q, - lambda x, y: x - y) - p[0] = make_sentence('ERROR', r) - - -def p_stop_raise(p): - """ statement : STOP expr CO - | STOP expr NEWLINE - | STOP CO - | STOP NEWLINE - """ - q = p[2] - if not isinstance(q, Symbol): - q = make_number(9, lineno=p.lineno(1)) - - z = make_number(1, lineno=p.lineno(1)) - r = make_binary(p.lineno(1), 'MINUS', - make_typecast(TYPE.ubyte, q, p.lineno(1)), z, - lambda x, y: x - y) - p[0] = make_sentence('STOP', r) - - def p_for_sentence_start(p): """ for_start : FOR ID EQ expr TO expr step """ @@ -1470,6 +1498,36 @@ def p_for_sentence_start(p): p[0] = make_sentence('FOR', variable, expr1, expr2, expr3) +def p_end(p): + """ statement : END expr + | END + """ + q = make_number(0, lineno=p.lineno(1)) if len(p) == 2 else p[2] + p[0] = make_sentence('END', q) + + +def p_error_raise(p): + """ statement : ERROR expr + """ + q = make_number(1, lineno=p.lineno(2)) + r = make_binary(p.lineno(1), 'MINUS', + make_typecast(TYPE.ubyte, p[2], p.lineno(1)), q, + lambda x, y: x - y) + p[0] = make_sentence('ERROR', r) + + +def p_stop_raise(p): + """ statement : STOP expr + | STOP + """ + q = make_number(9, lineno=p.lineno(1)) if len(p) == 2 else p[2] + z = make_number(1, lineno=p.lineno(1)) + r = make_binary(p.lineno(1), 'MINUS', + make_typecast(TYPE.ubyte, q, p.lineno(1)), z, + lambda x, y: x - y) + p[0] = make_sentence('STOP', r) + + def p_step(p): """ step : """ @@ -1493,14 +1551,11 @@ def p_loop(p): def p_do_loop(p): - """ statement : do_start program label_loop CO - | do_start program label_loop NEWLINE - | do_start label_loop CO - | do_start label_loop NEWLINE - | DO label_loop CO - | DO label_loop NEWLINE - """ - if len(p) > 4: + """ statement : do_start program_co label_loop + | do_start label_loop + | DO label_loop + """ + if len(p) == 4: q = make_block(p[2], p[3]) else: q = p[2] @@ -1517,14 +1572,11 @@ def p_do_loop(p): def p_do_loop_until(p): - """ statement : do_start program label_loop UNTIL expr CO - | do_start program label_loop UNTIL expr NEWLINE - | do_start label_loop UNTIL expr CO - | do_start label_loop UNTIL expr NEWLINE - | DO label_loop UNTIL expr NEWLINE - | DO label_loop UNTIL expr CO - """ - if len(p) > 6: + """ statement : do_start program_co label_loop UNTIL expr + | do_start label_loop UNTIL expr + | DO label_loop UNTIL expr + """ + if len(p) == 6: q = make_block(p[2], p[3]) r = p[5] else: @@ -1544,8 +1596,7 @@ def p_do_loop_until(p): def p_data(p): - """ statement : DATA arguments CO - | DATA arguments NEWLINE + """ statement : DATA arguments """ label_ = make_label(gl.DATA_PTR_CURRENT, lineno=p.lineno(1)) datas_ = [] @@ -1584,25 +1635,21 @@ def p_data(p): def p_restore(p): - """ statement : RESTORE CO - | RESTORE NEWLINE - | RESTORE ID CO - | RESTORE ID NEWLINE - | RESTORE NUMBER CO - | RESTORE NUMBER NEWLINE - """ - if len(p) == 3: + """ statement : RESTORE + | RESTORE ID + | RESTORE NUMBER + """ + if len(p) == 2: id_ = '__DATA__{0}'.format(len(gl.DATAS)) else: id_ = p[2] - lbl = check_and_make_label(id_, p.lineno(2)) + lbl = check_and_make_label(id_, p.lineno(1)) p[0] = make_sentence('RESTORE', lbl) def p_read(p): - """ statement : READ arguments CO - | READ arguments NEWLINE + """ statement : READ arguments """ gl.DATA_IS_USED = True reads = [] @@ -1644,14 +1691,11 @@ def p_read(p): def p_do_loop_while(p): - """ statement : do_start program label_loop WHILE expr CO - | do_start program label_loop WHILE expr NEWLINE - | do_start label_loop WHILE expr CO - | do_start label_loop WHILE expr NEWLINE - | DO label_loop WHILE expr NEWLINE - | DO label_loop WHILE expr CO - """ - if len(p) > 6: + """ statement : do_start program_co label_loop WHILE expr + | do_start label_loop WHILE expr + | DO label_loop WHILE expr + """ + if len(p) == 6: q = make_block(p[2], p[3]) r = p[5] else: @@ -1671,10 +1715,9 @@ def p_do_loop_while(p): def p_do_while_loop(p): - """ statement : do_while_start program LOOP CO - | do_while_start program LOOP NEWLINE - | do_while_start LOOP CO - | do_while_start LOOP NEWLINE + """ statement : do_while_start program_co LOOP + | do_while_start co_statements_co LOOP + | do_while_start LOOP """ r = p[1] q = p[2] @@ -1689,10 +1732,9 @@ def p_do_while_loop(p): def p_do_until_loop(p): - """ statement : do_until_start program LOOP CO - | do_until_start program LOOP NEWLINE - | do_until_start LOOP CO - | do_until_start LOOP NEWLINE + """ statement : do_until_start program_co LOOP + | do_until_start co_statements_co LOOP + | do_until_start LOOP """ r = p[1] q = p[2] @@ -1707,16 +1749,14 @@ def p_do_until_loop(p): def p_do_while_start(p): - """ do_while_start : DO WHILE expr CO - | DO WHILE expr NEWLINE + """ do_while_start : DO WHILE expr """ p[0] = p[3] gl.LOOPS.append(('DO',)) def p_do_until_start(p): - """ do_until_start : DO UNTIL expr CO - | DO UNTIL expr NEWLINE + """ do_until_start : DO UNTIL expr """ p[0] = p[3] gl.LOOPS.append(('DO',)) @@ -1730,10 +1770,10 @@ def p_do_start(p): def p_label_end_while(p): - """ label_end_while : LABEL END WHILE - | LABEL WEND - | END WHILE + """ label_end_while : LABEL WEND + | LABEL END WHILE | WEND + | END WHILE """ if p[1] in ('WEND', 'END'): p[0] = None @@ -1742,17 +1782,11 @@ def p_label_end_while(p): def p_while_sentence(p): - """ statement : while_start program label_end_while CO - | while_start program label_end_while NEWLINE - | while_start label_end_while CO - | while_start label_end_while NEWLINE + """ statement : while_start co_statements_co label_end_while + | while_start program_co label_end_while """ gl.LOOPS.pop() - - if len(p) > 4: - q = make_block(p[2], p[3]) - else: - q = p[2] + q = make_block(p[2], p[3]) if is_number(p[1]): if p[1].value == 0: @@ -1780,12 +1814,9 @@ def p_while_start(p): def p_exit(p): - """ statement : EXIT WHILE CO - | EXIT WHILE NEWLINE - | EXIT DO CO - | EXIT DO NEWLINE - | EXIT FOR CO - | EXIT FOR NEWLINE + """ statement : EXIT WHILE + | EXIT DO + | EXIT FOR """ q = p[2] p[0] = make_sentence('EXIT_%s' % q) @@ -1798,12 +1829,9 @@ def p_exit(p): def p_continue(p): - """ statement : CONTINUE WHILE CO - | CONTINUE WHILE NEWLINE - | CONTINUE DO CO - | CONTINUE DO NEWLINE - | CONTINUE FOR CO - | CONTINUE FOR NEWLINE + """ statement : CONTINUE WHILE + | CONTINUE DO + | CONTINUE FOR """ q = p[2] p[0] = make_sentence('CONTINUE_%s' % q) @@ -1816,8 +1844,7 @@ def p_continue(p): def p_print_sentence(p): - """ statement : PRINT print_list CO - | PRINT print_list NEWLINE + """ statement : PRINT print_list """ global PRINT_IS_USED @@ -1918,8 +1945,7 @@ def p_print_list_tab(p): def p_on_goto(p): - """ statement : ON expr goto label_list CO - | ON expr goto label_list NEWLINE + """ statement : ON expr goto label_list """ expr = make_typecast(TYPE.ubyte, p[2], p.lineno(1)) p[0] = make_sentence('ON_' + p[3], expr, *p[4]) @@ -1943,8 +1969,7 @@ def p_label_list_list(p): def p_return(p): - """ statement : RETURN CO - | RETURN NEWLINE + """ statement : RETURN """ if not FUNCTION_LEVEL: # At less one level, otherwise, this return is from a GOSUB p[0] = make_sentence('RETURN') @@ -1959,8 +1984,7 @@ def p_return(p): def p_return_expr(p): - """ statement : RETURN expr CO - | RETURN expr NEWLINE + """ statement : RETURN expr """ if not FUNCTION_LEVEL: # At less one level syntax_error(p.lineno(1), 'Syntax Error: Returning value out of FUNCTION') @@ -1992,18 +2016,15 @@ def p_return_expr(p): def p_pause(p): - """ statement : PAUSE expr CO - | PAUSE expr NEWLINE + """ statement : PAUSE expr """ p[0] = make_sentence('PAUSE', make_typecast(TYPE.uinteger, p[2], p.lineno(1))) def p_poke(p): - """ statement : POKE expr COMMA expr CO - | POKE expr COMMA expr NEWLINE - | POKE LP expr COMMA expr RP CO - | POKE LP expr COMMA expr RP NEWLINE + """ statement : POKE expr COMMA expr + | POKE LP expr COMMA expr RP """ i = 2 if isinstance(p[2], Symbol) or p[2] is None else 3 if p[i] is None or p[i + 2] is None: @@ -2011,30 +2032,26 @@ def p_poke(p): return p[0] = make_sentence('POKE', make_typecast(TYPE.uinteger, p[i], p.lineno(i + 1)), - make_typecast(TYPE.ubyte, p[i + 2], p.lineno(i + 3))) + make_typecast(TYPE.ubyte, p[i + 2], p.lineno(i + 1))) def p_poke2(p): - """ statement : POKE numbertype expr COMMA expr CO - | POKE numbertype expr COMMA expr NEWLINE - | POKE LP numbertype expr COMMA expr RP CO - | POKE LP numbertype expr COMMA expr RP NEWLINE + """ statement : POKE numbertype expr COMMA expr + | POKE LP numbertype expr COMMA expr RP """ i = 2 if isinstance(p[2], Symbol) or p[2] is None else 3 if p[i + 1] is None or p[i + 3] is None: p[0] = None return p[0] = make_sentence('POKE', - make_typecast(TYPE.uinteger, p[i + 1], - p.lineno(i + 2)), - make_typecast(p[i], p[i + 3], p.lineno(i + 4))) + make_typecast(TYPE.uinteger, p[i + 1], p.lineno(i + 2)), + make_typecast(p[i], p[i + 3], p.lineno(i + 3)) + ) def p_poke3(p): - """ statement : POKE numbertype COMMA expr COMMA expr CO - | POKE numbertype COMMA expr COMMA expr NEWLINE - | POKE LP numbertype COMMA expr COMMA expr RP CO - | POKE LP numbertype COMMA expr COMMA expr RP NEWLINE + """ statement : POKE numbertype COMMA expr COMMA expr + | POKE LP numbertype COMMA expr COMMA expr RP """ i = 2 if isinstance(p[2], Symbol) or p[2] is None else 3 if p[i + 2] is None or p[i + 4] is None: @@ -2047,43 +2064,30 @@ def p_poke3(p): def p_out(p): - """ statement : OUT expr COMMA expr CO - | OUT expr COMMA expr NEWLINE + """ statement : OUT expr COMMA expr """ p[0] = make_sentence('OUT', make_typecast(TYPE.uinteger, p[2], p.lineno(3)), - make_typecast(TYPE.ubyte, p[4], p.lineno(5))) + make_typecast(TYPE.ubyte, p[4], p.lineno(4))) def p_simple_instruction(p): - """ statement : ITALIC expr CO - | ITALIC expr NEWLINE - | BOLD expr CO - | BOLD expr NEWLINE - | INK expr CO - | INK expr NEWLINE - | PAPER expr CO - | PAPER expr NEWLINE - | BRIGHT expr CO - | BRIGHT expr NEWLINE - | FLASH expr CO - | FLASH expr NEWLINE - | OVER expr CO - | OVER expr NEWLINE - | INVERSE expr CO - | INVERSE expr NEWLINE - """ - p[0] = make_sentence(p[1], make_typecast(TYPE.ubyte, p[2], p.lineno(3))) + """ statement : ITALIC expr + | BOLD expr + | INK expr + | PAPER expr + | BRIGHT expr + | FLASH expr + | OVER expr + | INVERSE expr + """ + p[0] = make_sentence(p[1], make_typecast(TYPE.ubyte, p[2], p.lineno(1))) def p_save_code(p): - """ statement : SAVE expr CODE expr COMMA expr CO - | SAVE expr CODE expr COMMA expr NEWLINE - | SAVE expr ID NEWLINE - | SAVE expr ID CO - | SAVE expr ARRAY_ID CO - | SAVE expr ARRAY_ID NEWLINE - + """ statement : SAVE expr CODE expr COMMA expr + | SAVE expr ID + | SAVE expr ARRAY_ID """ if p[2].type_ != TYPE.string: api.errmsg.syntax_error_expected_string(p.lineno(1), p[2].type_) @@ -2105,17 +2109,14 @@ def p_save_code(p): def p_save_data(p): - """ statement : SAVE expr DATA CO - | SAVE expr DATA NEWLINE - | SAVE expr DATA ID CO - | SAVE expr DATA ID NEWLINE - | SAVE expr DATA ID LP RP CO - | SAVE expr DATA ID LP RP NEWLINE + """ statement : SAVE expr DATA + | SAVE expr DATA ID + | SAVE expr DATA ID LP RP """ if p[2].type_ != TYPE.string: api.errmsg.syntax_error_expected_string(p.lineno(1), p[2].type_) - if len(p) != 5: + if len(p) != 4: entry = SYMBOL_TABLE.access_id(p[4], p.lineno(4)) if entry is None: p[0] = None @@ -2130,12 +2131,11 @@ def p_save_data(p): else: length = make_number(entry.type_.size, lineno=p.lineno(4)) else: - access = SYMBOL_TABLE.access_id('.ZXBASIC_USER_DATA', p.lineno(4)) - start = make_unary(p.lineno(4), 'ADDRESS', access, type_=TYPE.uinteger) + access = SYMBOL_TABLE.access_id('.ZXBASIC_USER_DATA', p.lineno(3)) + start = make_unary(p.lineno(3), 'ADDRESS', access, type_=TYPE.uinteger) - access = SYMBOL_TABLE.access_id('.ZXBASIC_USER_DATA_LEN', p.lineno(4)) - length = make_unary(p.lineno(4), 'ADDRESS', access, - type_=TYPE.uinteger) + access = SYMBOL_TABLE.access_id('.ZXBASIC_USER_DATA_LEN', p.lineno(3)) + length = make_unary(p.lineno(3), 'ADDRESS', access, type_=TYPE.uinteger) p[0] = make_sentence(p[1], p[2], start, length) @@ -2148,19 +2148,15 @@ def p_load_or_verify(p): def p_load_code(p): - """ statement : load_or_verify expr ID CO - | load_or_verify expr CODE CO - | load_or_verify expr CODE expr CO - | load_or_verify expr CODE expr COMMA expr CO - | load_or_verify expr ID NEWLINE - | load_or_verify expr CODE NEWLINE - | load_or_verify expr CODE expr NEWLINE - | load_or_verify expr CODE expr COMMA expr NEWLINE + """ statement : load_or_verify expr ID + | load_or_verify expr CODE + | load_or_verify expr CODE expr + | load_or_verify expr CODE expr COMMA expr """ if p[2].type_ != TYPE.string: api.errmsg.syntax_error_expected_string(p.lineno(3), p[2].type_) - if len(p) == 5: + if len(p) == 4: if p[3].upper() not in ('SCREEN', 'SCREEN$', 'CODE'): syntax_error(p.lineno(3), 'Unexpected "%s" ID. Expected "SCREEN$" instead' % p[3]) return None @@ -2174,7 +2170,7 @@ def p_load_code(p): else: start = make_typecast(TYPE.uinteger, p[4], p.lineno(3)) - if len(p) == 6: + if len(p) == 5: length = make_number(0, lineno=p.lineno(3)) else: length = make_typecast(TYPE.uinteger, p[6], p.lineno(5)) @@ -2183,17 +2179,14 @@ def p_load_code(p): def p_load_data(p): - """ statement : load_or_verify expr DATA CO - | load_or_verify expr DATA NEWLINE - | load_or_verify expr DATA ID CO - | load_or_verify expr DATA ID NEWLINE - | load_or_verify expr DATA ID LP RP CO - | load_or_verify expr DATA ID LP RP NEWLINE + """ statement : load_or_verify expr DATA + | load_or_verify expr DATA ID + | load_or_verify expr DATA ID LP RP """ if p[2].type_ != TYPE.string: api.errmsg.syntax_error_expected_string(p.lineno(1), p[2].type_) - if len(p) != 5: + if len(p) != 4: entry = SYMBOL_TABLE.access_id(p[4], p.lineno(4)) if entry is None: p[0] = None @@ -2207,12 +2200,11 @@ def p_load_data(p): else: length = make_number(entry.type_.size, lineno=p.lineno(4)) else: - entry = SYMBOL_TABLE.access_id('.ZXBASIC_USER_DATA', p.lineno(4)) - start = make_unary(p.lineno(4), 'ADDRESS', entry, type_=TYPE.uinteger) + entry = SYMBOL_TABLE.access_id('.ZXBASIC_USER_DATA', p.lineno(3)) + start = make_unary(p.lineno(3), 'ADDRESS', entry, type_=TYPE.uinteger) - entry = SYMBOL_TABLE.access_id('.ZXBASIC_USER_DATA_LEN', p.lineno(4)) - length = make_unary(p.lineno(4), 'ADDRESS', entry, - type_=TYPE.uinteger) + entry = SYMBOL_TABLE.access_id('.ZXBASIC_USER_DATA_LEN', p.lineno(3)) + length = make_unary(p.lineno(3), 'ADDRESS', entry, type_=TYPE.uinteger) p[0] = make_sentence(p[1], p[2], start, length) @@ -2420,7 +2412,7 @@ def p_number_line(p): def p_expr_string(p): - """ bexpr : string + """ bexpr : string %prec ID """ p[0] = p[1] @@ -2579,7 +2571,7 @@ def p_expr_bexpr(p): def p_expr_funccall(p): - """ bexpr : func_call + """ bexpr : func_call %prec ID """ p[0] = p[1] @@ -2679,7 +2671,7 @@ def p_arguments(p): def p_argument(p): - """ arguments : expr + """ arguments : expr %prec ID """ p[0] = make_arg_list(make_argument(p[1], p.lineno(1))) @@ -2776,7 +2768,7 @@ def p_function_header(p): def p_function_error(p): - """ function_declaration : function_header program END error NEWLINE + """ function_declaration : function_header program_co END error """ p[0] = None syntax_error(p.lineno(3), "Unexpected token 'END'. Expected 'END FUNCTION' or 'END SUB' instead.") @@ -2875,8 +2867,10 @@ def p_param_def_type(p): def p_function_body(p): - """ function_body : program END FUNCTION - | program END SUB + """ function_body : program_co END FUNCTION + | program_co END SUB + | co_statements_co END FUNCTION + | co_statements_co END SUB | END FUNCTION | END SUB """ @@ -2928,7 +2922,7 @@ def p_type(p): # Some preprocessor directives def p_preprocessor_line(p): - """ preproc_line : preproc_line_line NEWLINE + """ preproc_line : preproc_line_line """ @@ -2996,7 +2990,7 @@ def p_expr_usr(p): def p_expr_rnd(p): - """ bexpr : RND + """ bexpr : RND %prec ID | RND LP RP """ p[0] = make_builtin(p.lineno(1), 'RND', None, type_=TYPE.float_) From 38c0e3e0b7a521aad04c7ae317ae32b02cff7693 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 18 Nov 2017 13:57:51 +0100 Subject: [PATCH 115/247] opt: use visitor for generic if optimization --- api/optimize.py | 11 +++++++++ symbols/sentence.py | 3 ++- tests/functional/ifempty.asm | 37 ++++++++++++++++++++++++++++++ tests/functional/ifempty.bas | 6 +++++ tests/functional/ifemptylabel.asm | 38 +++++++++++++++++++++++++++++++ tests/functional/ifemptylabel.bas | 8 +++++++ zxbparser.py | 34 ++++++++------------------- 7 files changed, 112 insertions(+), 25 deletions(-) create mode 100644 tests/functional/ifempty.asm create mode 100644 tests/functional/ifempty.bas create mode 100644 tests/functional/ifemptylabel.asm create mode 100644 tests/functional/ifemptylabel.bas diff --git a/api/optimize.py b/api/optimize.py index 416cdbf22..32c744182 100644 --- a/api/optimize.py +++ b/api/optimize.py @@ -157,6 +157,17 @@ def visit_UNARY(self, node): else: yield (yield self.generic_visit(node)) + def visit_IF(self, node): + if self.O_LEVEL >= 1: + else_ = node.children[2] if len(node.children) == 3 else self.NOP + if chk.is_number(node.children[0]): # constant condition + if node.children[0].value: # always then + yield node.children[1] + else: + yield else_ + return + yield (yield self.generic_visit(node)) + @staticmethod def generic_visit(node): for i in range(len(node.children)): diff --git a/symbols/sentence.py b/symbols/sentence.py index d5c671e1c..8ecb9f84f 100644 --- a/symbols/sentence.py +++ b/symbols/sentence.py @@ -15,11 +15,12 @@ class SymbolSENTENCE(Symbol): """ Defines a BASIC SENTENCE object. e.g. 'BORDER'. """ - def __init__(self, keyword, *args): + def __init__(self, keyword, *args, **kwargs): """ keyword = 'BORDER', or 'PRINT' """ super(SymbolSENTENCE, self).__init__(*(x for x in args if x is not None)) self.keyword = keyword + self.lineno = kwargs.get('lineno', None) @property def args(self): diff --git a/tests/functional/ifempty.asm b/tests/functional/ifempty.asm new file mode 100644 index 000000000..49d4ccd19 --- /dev/null +++ b/tests/functional/ifempty.asm @@ -0,0 +1,37 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_i: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifempty.bas b/tests/functional/ifempty.bas new file mode 100644 index 000000000..ebe82d594 --- /dev/null +++ b/tests/functional/ifempty.bas @@ -0,0 +1,6 @@ + +REM for -O1 or higher, this will produce no output +DIM i as Byte + +If 0 i = i + 1 + diff --git a/tests/functional/ifemptylabel.asm b/tests/functional/ifemptylabel.asm new file mode 100644 index 000000000..aeb28d68c --- /dev/null +++ b/tests/functional/ifemptylabel.asm @@ -0,0 +1,38 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + jp __LABEL__Here + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00, 00, 00, 00, 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifemptylabel.bas b/tests/functional/ifemptylabel.bas new file mode 100644 index 000000000..2c6e1ea58 --- /dev/null +++ b/tests/functional/ifemptylabel.bas @@ -0,0 +1,8 @@ + +IF 0 THEN +Here: + a = a + 1 +END IF + +GOTO Here + diff --git a/zxbparser.py b/zxbparser.py index db66f917e..23e2937ed 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -210,10 +210,10 @@ def make_strslice(lineno, s, lower, upper): return symbols.STRSLICE.make_node(lineno, s, lower, upper) -def make_sentence(sentence, *args): +def make_sentence(sentence, *args, **kwargs): """ Wrapper: returns a Sentence node """ - return symbols.SENTENCE(sentence, *args) + return symbols.SENTENCE(*([sentence] + list(args)), **kwargs) def make_asm_sentence(asm, lineno): @@ -1177,14 +1177,14 @@ def p_if_sentence(p): p[0] = endif_ return - if is_number(cond_): - if OPTIONS.optimization.value > 0: - if not cond_.value: - p[0] = endif_ - return - else: - p[0] = make_block(stat_, endif_) - return + # if is_number(cond_): + # if OPTIONS.optimization.value > 0: + # if not cond_.value: + # p[0] = endif_ + # return + # else: + # p[0] = make_block(stat_, endif_) + # return p[0] = make_sentence('IF', cond_, make_block(stat_, endif_)) @@ -1227,23 +1227,9 @@ def p_single_line_if(p): """ cond_ = p[1] stat_ = p[2] - # endif_ = make_nop() if is_null(stat_): api.errmsg.warning_empty_if(p.lineno(1)) - # TODO: Optimize this in the visitor since this rule is also use in the ELSE part - # p[0] = endif_ - return - - # TODO: Optimize this in the visitor since this rule is also use in the ELSE part - # if is_number(cond_): - # if OPTIONS.optimization.value > 0: - # if not cond_.value: - # p[0] = endif_ - # return - # else: - # p[0] = stat_ - # return p[0] = make_sentence('IF', cond_, stat_) From 54cbe176eb1bb66de49a40ad76175f93eb807935 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 19 Nov 2017 20:18:13 +0100 Subject: [PATCH 116/247] code cleanup * Remove TODO from api/optimize.py * Add code regions for FOR and IF sentences * Put definition within FOR region --- api/optimize.py | 1 - zxbparser.py | 42 +++++++++++++++++++++++------------------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/api/optimize.py b/api/optimize.py index 32c744182..c909c9c57 100644 --- a/api/optimize.py +++ b/api/optimize.py @@ -21,7 +21,6 @@ def __init__(self, obj): self.obj = obj -# TODO: Implement as a visitor with generators class OptimizerVisitor(NodeVisitor): """ Implements some optimizations """ diff --git a/zxbparser.py b/zxbparser.py index 23e2937ed..bee811ba7 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -1153,13 +1153,7 @@ def p_go(p): p[0] += p[2] -def p_endif(p): - """ endif : END IF - | LABEL END IF - """ - p[0] = make_nop() if p[1] == 'END' else make_label(p[1], p.lineno(1)) - - +# region [IF sentence] def p_if_sentence(p): """ statement : if_then_part NEWLINE program_co endif | if_then_part NEWLINE endif @@ -1189,6 +1183,13 @@ def p_if_sentence(p): p[0] = make_sentence('IF', cond_, make_block(stat_, endif_)) +def p_endif(p): + """ endif : END IF + | LABEL END IF + """ + p[0] = make_nop() if p[1] == 'END' else make_label(p[1], p.lineno(1)) + + def p_statement_if(p): """ statement : if_inline %prec RP """ @@ -1407,8 +1408,10 @@ def p_then(p): """ then : | THEN """ +# endregion +# region [FOR sentence] def p_for_sentence(p): """ statement : for_start program_co label_next | for_start co_statements_co label_next @@ -1484,6 +1487,19 @@ def p_for_sentence_start(p): p[0] = make_sentence('FOR', variable, expr1, expr2, expr3) +def p_step(p): + """ step : + """ + p[0] = make_number(1, lineno=p.lexer.lineno) + + +def p_step_expr(p): + """ step : STEP expr + """ + p[0] = p[2] +# endregion + + def p_end(p): """ statement : END expr | END @@ -1514,18 +1530,6 @@ def p_stop_raise(p): p[0] = make_sentence('STOP', r) -def p_step(p): - """ step : - """ - p[0] = make_number(1, lineno=p.lexer.lineno) - - -def p_step_expr(p): - """ step : STEP expr - """ - p[0] = p[2] - - def p_loop(p): """ label_loop : LABEL LOOP | LOOP From 8ceefb34d640d6e134aaf5ac843bd391f366314d Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 20 Nov 2017 16:03:56 +0100 Subject: [PATCH 117/247] bufix: Empty ELSE --- api/optimize.py | 14 +++++-- tests/functional/ifempty2.asm | 74 +++++++++++++++++++++++++++++++++ tests/functional/ifempty2.bas | 5 +++ tests/functional/ifempty3.asm | 78 +++++++++++++++++++++++++++++++++++ tests/functional/ifempty3.bas | 5 +++ zxbparser.py | 2 +- 6 files changed, 174 insertions(+), 4 deletions(-) create mode 100644 tests/functional/ifempty2.asm create mode 100644 tests/functional/ifempty2.bas create mode 100644 tests/functional/ifempty3.asm create mode 100644 tests/functional/ifempty3.bas diff --git a/api/optimize.py b/api/optimize.py index c909c9c57..0f9f72704 100644 --- a/api/optimize.py +++ b/api/optimize.py @@ -158,13 +158,21 @@ def visit_UNARY(self, node): def visit_IF(self, node): if self.O_LEVEL >= 1: + expr_ = node.children[0] + then_ = node.children[1] else_ = node.children[2] if len(node.children) == 3 else self.NOP - if chk.is_number(node.children[0]): # constant condition - if node.children[0].value: # always then - yield node.children[1] + + if chk.is_null(then_, expr_): + yield self.NOP + return + + if chk.is_number(expr_): # constant condition + if expr_.value: # always then + yield then_ else: yield else_ return + yield (yield self.generic_visit(node)) @staticmethod diff --git a/tests/functional/ifempty2.asm b/tests/functional/ifempty2.asm new file mode 100644 index 000000000..9a842732a --- /dev/null +++ b/tests/functional/ifempty2.asm @@ -0,0 +1,74 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld h, 0 + ld a, (_i) + call __LTI8 + or a + jp nz, __LABEL1 +__LABEL0: + ld a, (_i) + inc a + ld (_i), a +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "lti8.asm" + +#line 1 "lei8.asm" + +__LEI8: ; Signed <= comparison for 8bit int + ; A <= H (registers) + PROC + LOCAL checkParity + sub h + jr nz, __LTI + inc a + ret + +__LTI8: ; Test 8 bit values A < H + sub h + +__LTI: ; Generic signed comparison + jp po, checkParity + xor 0x80 +checkParity: + ld a, 0 ; False + ret p + inc a ; True + ret + ENDP +#line 2 "lti8.asm" +#line 28 "ifempty2.bas" + +ZXBASIC_USER_DATA: +_i: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifempty2.bas b/tests/functional/ifempty2.bas new file mode 100644 index 000000000..20403b4ec --- /dev/null +++ b/tests/functional/ifempty2.bas @@ -0,0 +1,5 @@ +DIM i as Byte + +IF i < 0 THEN : ELSE i = i + 1 + + diff --git a/tests/functional/ifempty3.asm b/tests/functional/ifempty3.asm new file mode 100644 index 000000000..25088ecf5 --- /dev/null +++ b/tests/functional/ifempty3.asm @@ -0,0 +1,78 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld h, 0 + ld a, (_i) + call __LTI8 + or a + jp z, __LABEL0 + ld a, (_i) + dec a + ld (_i), a + jp __LABEL1 +__LABEL0: + ld a, (_i) + inc a + ld (_i), a +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "lti8.asm" + +#line 1 "lei8.asm" + +__LEI8: ; Signed <= comparison for 8bit int + ; A <= H (registers) + PROC + LOCAL checkParity + sub h + jr nz, __LTI + inc a + ret + +__LTI8: ; Test 8 bit values A < H + sub h + +__LTI: ; Generic signed comparison + jp po, checkParity + xor 0x80 +checkParity: + ld a, 0 ; False + ret p + inc a ; True + ret + ENDP +#line 2 "lti8.asm" +#line 32 "ifempty3.bas" + +ZXBASIC_USER_DATA: +_i: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifempty3.bas b/tests/functional/ifempty3.bas new file mode 100644 index 000000000..6d5f3ed11 --- /dev/null +++ b/tests/functional/ifempty3.bas @@ -0,0 +1,5 @@ +DIM i as Byte + +IF i < 0 THEN i = i - 1 ELSE i = i + 1 + + diff --git a/zxbparser.py b/zxbparser.py index bee811ba7..32f077881 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -504,7 +504,7 @@ def p_co_statements_co(p): | co_statements_co CO | CO """ - p[0] = p[1] if len(p) == 3 else None + p[0] = p[1] if len(p) == 3 else make_nop() def p_co_statements(p): From 8a755fb7cc75552079bd47bf7d625a08b7b59145 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 20 Nov 2017 16:26:34 +0100 Subject: [PATCH 118/247] add function is_LABEL to examine nodes --- api/check.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/api/check.py b/api/check.py index 5ac94aed2..f915d7b1b 100644 --- a/api/check.py +++ b/api/check.py @@ -233,6 +233,10 @@ def is_SYMBOL(token, *symbols): return True +def is_LABEL(*p): + return is_SYMBOL('LABEL', *p) + + def is_string(*p): return is_SYMBOL('STRING', *p) From baf0d525c02ade353ca3202234d3ef5075c5de79 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 20 Nov 2017 23:54:14 +0100 Subject: [PATCH 119/247] bugfix: do not optimize THEN accessed IF blocks IF a block in the THEN part is accessed also from a GOTO statement (yes, dirty programming but possible), this block cannot be removed. --- api/check.py | 16 +++++++ api/optimize.py | 15 +++++-- tests/functional/ifemptylabel.bas | 8 ---- tests/functional/ifemptylabel1.asm | 44 +++++++++++++++++++ tests/functional/ifemptylabel1.bas | 11 +++++ .../{ifemptylabel.asm => ifemptylabel2.asm} | 5 ++- tests/functional/ifemptylabel2.bas | 13 ++++++ 7 files changed, 99 insertions(+), 13 deletions(-) delete mode 100644 tests/functional/ifemptylabel.bas create mode 100644 tests/functional/ifemptylabel1.asm create mode 100644 tests/functional/ifemptylabel1.bas rename tests/functional/{ifemptylabel.asm => ifemptylabel2.asm} (92%) create mode 100644 tests/functional/ifemptylabel2.bas diff --git a/api/check.py b/api/check.py index f915d7b1b..17397c06a 100644 --- a/api/check.py +++ b/api/check.py @@ -385,6 +385,22 @@ def is_dynamic(*p): # TODO: Explain this better return False +def is_block_accessed(block): + """ Returns True if a block is "accessed". A block of code is accessed if + it has a LABEL and it is used in a GOTO, GO SUB or @address access + :param block: A block of code (AST node) + :return: True / False depending if it has labels accessed or not + """ + if is_LABEL(block) and block.accessed: + return True + + for child in block.children: + if is_block_accessed(child): + return True + + return False + + def common_type(a, b): """ Returns a type which is common for both a and b types. Returns None if no common types allowed. diff --git a/api/optimize.py b/api/optimize.py index 0f9f72704..4b42d2ec3 100644 --- a/api/optimize.py +++ b/api/optimize.py @@ -162,19 +162,26 @@ def visit_IF(self, node): then_ = node.children[1] else_ = node.children[2] if len(node.children) == 3 else self.NOP - if chk.is_null(then_, expr_): + if chk.is_null(then_, else_): yield self.NOP return - if chk.is_number(expr_): # constant condition - if expr_.value: # always then + block_accessed = chk.is_block_accessed(then_) + if not block_accessed and chk.is_number(expr_): # constant condition + if expr_.value: # always true (then_) yield then_ - else: + else: # always false (else_) yield else_ return yield (yield self.generic_visit(node)) + def visit_LABEL(self, node): + if not node.accessed: + yield self.NOP + else: + yield node + @staticmethod def generic_visit(node): for i in range(len(node.children)): diff --git a/tests/functional/ifemptylabel.bas b/tests/functional/ifemptylabel.bas deleted file mode 100644 index 2c6e1ea58..000000000 --- a/tests/functional/ifemptylabel.bas +++ /dev/null @@ -1,8 +0,0 @@ - -IF 0 THEN -Here: - a = a + 1 -END IF - -GOTO Here - diff --git a/tests/functional/ifemptylabel1.asm b/tests/functional/ifemptylabel1.asm new file mode 100644 index 000000000..4121eaeb8 --- /dev/null +++ b/tests/functional/ifemptylabel1.asm @@ -0,0 +1,44 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + jp __LABEL1 +__LABEL__Here: + ld a, (_a) + inc a + ld (_a), a +__LABEL1: + jp __LABEL__Here + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifemptylabel1.bas b/tests/functional/ifemptylabel1.bas new file mode 100644 index 000000000..cd190e2ec --- /dev/null +++ b/tests/functional/ifemptylabel1.bas @@ -0,0 +1,11 @@ +DIM a as Byte +IF 0 THEN +Here: + a = a + 1 + IF 0 THEN + a = a + 2 + END IF +END IF + +GOTO Here + diff --git a/tests/functional/ifemptylabel.asm b/tests/functional/ifemptylabel2.asm similarity index 92% rename from tests/functional/ifemptylabel.asm rename to tests/functional/ifemptylabel2.asm index aeb28d68c..6ae3a0b88 100644 --- a/tests/functional/ifemptylabel.asm +++ b/tests/functional/ifemptylabel2.asm @@ -10,6 +10,9 @@ __START_PROGRAM: add hl, sp ld (__CALL_BACK__), hl ei + ld a, (_a) + inc a + ld (_a), a jp __LABEL__Here ld hl, 0 ld b, h @@ -30,7 +33,7 @@ __CALL_BACK__: ZXBASIC_USER_DATA: _a: - DEFB 00, 00, 00, 00, 00 + DEFB 00 ; Defines DATA END --> HEAP size is 0 ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP ; Defines USER DATA Length in bytes diff --git a/tests/functional/ifemptylabel2.bas b/tests/functional/ifemptylabel2.bas new file mode 100644 index 000000000..7e2fefdb2 --- /dev/null +++ b/tests/functional/ifemptylabel2.bas @@ -0,0 +1,13 @@ +DIM a as Byte +IF 1 THEN + a = a + 1 +ELSE +Here: + a = a + 1 + IF 0 THEN + a = a + 2 + END IF +END IF + +GOTO Here + From 4f95ed8d2a595a17e569293591dcae810abdcbf9 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 21 Nov 2017 00:17:13 +0100 Subject: [PATCH 120/247] bugfix: do not optimize ELSE accessed IF blocks IF a block in the ELSE part is accessed also from a GOTO statement (yes, dirty programming but possible), this block cannot be removed. --- tests/functional/ifemptylabel2.asm | 7 +++++++ tests/functional/ifemptylabel2.bas | 4 ++-- zxbparser.py | 8 -------- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/tests/functional/ifemptylabel2.asm b/tests/functional/ifemptylabel2.asm index 6ae3a0b88..085d796dd 100644 --- a/tests/functional/ifemptylabel2.asm +++ b/tests/functional/ifemptylabel2.asm @@ -13,6 +13,13 @@ __START_PROGRAM: ld a, (_a) inc a ld (_a), a + jp __LABEL1 +__LABEL0: +__LABEL__Here: + ld a, (_a) + add a, 2 + ld (_a), a +__LABEL1: jp __LABEL__Here ld hl, 0 ld b, h diff --git a/tests/functional/ifemptylabel2.bas b/tests/functional/ifemptylabel2.bas index 7e2fefdb2..1bc4c4cb6 100644 --- a/tests/functional/ifemptylabel2.bas +++ b/tests/functional/ifemptylabel2.bas @@ -3,9 +3,9 @@ IF 1 THEN a = a + 1 ELSE Here: - a = a + 1 + a = a + 2 IF 0 THEN - a = a + 2 + a = a + 3 END IF END IF diff --git a/zxbparser.py b/zxbparser.py index 32f077881..194c77fa7 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -1385,14 +1385,6 @@ def p_if_else(p): p[0] = endif return - if is_number(cond_): - if not cond_.value: - p[0] = make_block(else_, endif) - return - else: - p[0] = make_block(then_, endif) - return - if is_null(then_): cond_ = make_unary(p.lineno(1), 'NOT', cond_, lambda x: not x) p[0] = make_sentence('IF', cond_, make_block(else_, endif)) From 711778400abf4b99eb103d28b7c72f0d545a1b64 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 21 Nov 2017 00:17:30 +0100 Subject: [PATCH 121/247] added pending label optimization --- api/optimize.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/api/optimize.py b/api/optimize.py index 4b42d2ec3..06a4756d9 100644 --- a/api/optimize.py +++ b/api/optimize.py @@ -166,7 +166,7 @@ def visit_IF(self, node): yield self.NOP return - block_accessed = chk.is_block_accessed(then_) + block_accessed = chk.is_block_accessed(then_) or chk.is_block_accessed(else_) if not block_accessed and chk.is_number(expr_): # constant condition if expr_.value: # always true (then_) yield then_ @@ -176,8 +176,9 @@ def visit_IF(self, node): yield (yield self.generic_visit(node)) - def visit_LABEL(self, node): - if not node.accessed: + # TODO: ignore unused labels + def _visit_LABEL(self, node): + if self.O_LEVEL and not node.accessed: yield self.NOP else: yield node From 17e26611ee6331d1b3798943c85471b25fb8de41 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 21 Nov 2017 11:29:48 +0100 Subject: [PATCH 122/247] refact: uses generic if optimization --- api/optimize.py | 2 ++ symbols/sentence.py | 1 + tests/functional/ifempty4.asm | 37 ++++++++++++++++++++++++++++++++ tests/functional/ifempty4.bas | 5 +++++ tests/functional/test_errmsg.txt | 2 ++ zxbparser.py | 16 +------------- 6 files changed, 48 insertions(+), 15 deletions(-) create mode 100644 tests/functional/ifempty4.asm create mode 100644 tests/functional/ifempty4.bas diff --git a/api/optimize.py b/api/optimize.py index 06a4756d9..b6a5fee2b 100644 --- a/api/optimize.py +++ b/api/optimize.py @@ -3,6 +3,7 @@ from ast_ import NodeVisitor from .config import OPTIONS +import api.errmsg from api.errmsg import warning import api.check as chk from api.constants import TYPE @@ -163,6 +164,7 @@ def visit_IF(self, node): else_ = node.children[2] if len(node.children) == 3 else self.NOP if chk.is_null(then_, else_): + api.errmsg.warning_empty_if(node.lineno) yield self.NOP return diff --git a/symbols/sentence.py b/symbols/sentence.py index 8ecb9f84f..69bc989a4 100644 --- a/symbols/sentence.py +++ b/symbols/sentence.py @@ -18,6 +18,7 @@ class SymbolSENTENCE(Symbol): def __init__(self, keyword, *args, **kwargs): """ keyword = 'BORDER', or 'PRINT' """ + assert not kwargs or 'lineno' in kwargs super(SymbolSENTENCE, self).__init__(*(x for x in args if x is not None)) self.keyword = keyword self.lineno = kwargs.get('lineno', None) diff --git a/tests/functional/ifempty4.asm b/tests/functional/ifempty4.asm new file mode 100644 index 000000000..49d4ccd19 --- /dev/null +++ b/tests/functional/ifempty4.asm @@ -0,0 +1,37 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_i: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifempty4.bas b/tests/functional/ifempty4.bas new file mode 100644 index 000000000..23e7fa0cd --- /dev/null +++ b/tests/functional/ifempty4.bas @@ -0,0 +1,5 @@ + +DIM i as UByte +IF i < 0 THEN +END IF + diff --git a/tests/functional/test_errmsg.txt b/tests/functional/test_errmsg.txt index 550fc72c1..379f96f7a 100644 --- a/tests/functional/test_errmsg.txt +++ b/tests/functional/test_errmsg.txt @@ -94,3 +94,5 @@ read3.bas:9: 'x' is neither an array nor a function. read6.bas:12: Syntax error. Can only read a variable or an array element >>> process_file('data0.bas') data0.bas:2: 'b' is neither an array nor a function. +>>> process_file('ifempty4.bas') +ifempty4.bas:3: warning: Useless empty IF ignored diff --git a/zxbparser.py b/zxbparser.py index 194c77fa7..c96c4fbb8 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -1166,21 +1166,7 @@ def p_if_sentence(p): stat_ = make_nop() endif_ = p[3] - if is_null(stat_): - api.errmsg.warning_empty_if(p.lineno(2)) - p[0] = endif_ - return - - # if is_number(cond_): - # if OPTIONS.optimization.value > 0: - # if not cond_.value: - # p[0] = endif_ - # return - # else: - # p[0] = make_block(stat_, endif_) - # return - - p[0] = make_sentence('IF', cond_, make_block(stat_, endif_)) + p[0] = make_sentence('IF', cond_, make_block(stat_, endif_), lineno=p.lineno(2)) def p_endif(p): From fe5da7010e92184235dc93a874e1c8e3a2ee2300 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 21 Nov 2017 12:55:47 +0100 Subject: [PATCH 123/247] better coverage for IF empty case --- tests/functional/ifempty0.asm | 37 +++++++++++++++++++++++++++++ tests/functional/ifempty0.bas | 4 ++++ tests/functional/ifempty1.asm | 37 +++++++++++++++++++++++++++++ tests/functional/ifempty1.bas | 4 ++++ tests/functional/ifempty5.asm | 40 ++++++++++++++++++++++++++++++++ tests/functional/ifempty5.bas | 4 ++++ tests/functional/ifempty6.asm | 40 ++++++++++++++++++++++++++++++++ tests/functional/ifempty6.bas | 4 ++++ tests/functional/test_errmsg.txt | 7 ++++++ zxbparser.py | 23 ++---------------- 10 files changed, 179 insertions(+), 21 deletions(-) create mode 100644 tests/functional/ifempty0.asm create mode 100644 tests/functional/ifempty0.bas create mode 100644 tests/functional/ifempty1.asm create mode 100644 tests/functional/ifempty1.bas create mode 100644 tests/functional/ifempty5.asm create mode 100644 tests/functional/ifempty5.bas create mode 100644 tests/functional/ifempty6.asm create mode 100644 tests/functional/ifempty6.bas diff --git a/tests/functional/ifempty0.asm b/tests/functional/ifempty0.asm new file mode 100644 index 000000000..49d4ccd19 --- /dev/null +++ b/tests/functional/ifempty0.asm @@ -0,0 +1,37 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_i: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifempty0.bas b/tests/functional/ifempty0.bas new file mode 100644 index 000000000..6c3c067ae --- /dev/null +++ b/tests/functional/ifempty0.bas @@ -0,0 +1,4 @@ +DIM i as Byte + +IF i < 0 THEN : + diff --git a/tests/functional/ifempty1.asm b/tests/functional/ifempty1.asm new file mode 100644 index 000000000..49d4ccd19 --- /dev/null +++ b/tests/functional/ifempty1.asm @@ -0,0 +1,37 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_i: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifempty1.bas b/tests/functional/ifempty1.bas new file mode 100644 index 000000000..a3f9b596a --- /dev/null +++ b/tests/functional/ifempty1.bas @@ -0,0 +1,4 @@ +DIM i as Byte + +IF i < 0 THEN : END IF + diff --git a/tests/functional/ifempty5.asm b/tests/functional/ifempty5.asm new file mode 100644 index 000000000..57667f023 --- /dev/null +++ b/tests/functional/ifempty5.asm @@ -0,0 +1,40 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld a, (_i) + inc a + ld (_i), a + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_i: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifempty5.bas b/tests/functional/ifempty5.bas new file mode 100644 index 000000000..0c9707661 --- /dev/null +++ b/tests/functional/ifempty5.bas @@ -0,0 +1,4 @@ +DIM i as Byte + +IF 1 THEN i = i + 1: END IF + diff --git a/tests/functional/ifempty6.asm b/tests/functional/ifempty6.asm new file mode 100644 index 000000000..a5cebffce --- /dev/null +++ b/tests/functional/ifempty6.asm @@ -0,0 +1,40 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld a, (_i) + dec a + ld (_i), a + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_i: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifempty6.bas b/tests/functional/ifempty6.bas new file mode 100644 index 000000000..a5d238ebd --- /dev/null +++ b/tests/functional/ifempty6.bas @@ -0,0 +1,4 @@ +DIM i as Byte + +IF 0 THEN i = i + 1 ELSE i = i - 1: END IF + diff --git a/tests/functional/test_errmsg.txt b/tests/functional/test_errmsg.txt index 379f96f7a..5306846b9 100644 --- a/tests/functional/test_errmsg.txt +++ b/tests/functional/test_errmsg.txt @@ -96,3 +96,10 @@ read6.bas:12: Syntax error. Can only read a variable or an array element data0.bas:2: 'b' is neither an array nor a function. >>> process_file('ifempty4.bas') ifempty4.bas:3: warning: Useless empty IF ignored +>>> process_file('ifempty1.bas') +ifempty1.bas:3: warning: Useless empty IF ignored +>>> process_file('ifempty5.bas') +ifempty5.bas:3: warning: Condition is always True +>>> process_file('ifempty0.bas') +ifempty0.bas:3: warning: Useless empty IF ignored + diff --git a/zxbparser.py b/zxbparser.py index c96c4fbb8..47bb131a6 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -1189,22 +1189,7 @@ def p_statement_if_then_endif(p): cond_ = p[1] stat_ = p[2] endif_ = p[3] - - if is_null(stat_): - api.errmsg.warning_empty_if(p.lineno(1)) - p[0] = endif_ - return - - if is_number(cond_): - if OPTIONS.optimization.value > 0: - if not cond_.value: - p[0] = endif_ - return - else: - p[0] = make_block(stat_, endif_) - return - - p[0] = make_sentence('IF', cond_, make_block(stat_, endif_)) + p[0] = make_sentence('IF', cond_, make_block(stat_, endif_), lineno=p.lineno(1)) def p_single_line_if(p): @@ -1214,11 +1199,7 @@ def p_single_line_if(p): """ cond_ = p[1] stat_ = p[2] - - if is_null(stat_): - api.errmsg.warning_empty_if(p.lineno(1)) - - p[0] = make_sentence('IF', cond_, stat_) + p[0] = make_sentence('IF', cond_, stat_, lineno=p.lineno(1)) def p_if_elseif(p): From dd68391b61102604b15005c49d5053d1d548b623 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 21 Nov 2017 13:40:51 +0100 Subject: [PATCH 124/247] refact: simpler grammar for ELSEIF --- zxbparser.py | 79 +++++++++++++++++++++++++--------------------------- 1 file changed, 38 insertions(+), 41 deletions(-) diff --git a/zxbparser.py b/zxbparser.py index 47bb131a6..629512cc3 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -1226,70 +1226,67 @@ def p_if_elseif(p): p[0] = make_sentence('IF', cond_, stats_, eliflist) -def p_elseif_list(p): - """ elseiflist : ELSEIF expr then program_co endif - | LABEL ELSEIF expr then program_co endif - | ELSEIF expr then program_co else_part - | LABEL ELSEIF expr then program_co else_part +def p_elseif_part(p): + """ elseif_expr : ELSEIF expr then + | LABEL ELSEIF expr then """ if p[1] == 'ELSEIF': - p1 = make_nop() # No label - p2 = p[2] - p4 = p[4] - p5 = p[5] + label_ = make_nop() # No label + cond_ = p[2] else: - p1 = make_label(p[1], p.lineno(1)) - p2 = p[3] - p4 = p[5] - p5 = p[6] + label_ = make_label(p[1], p.lineno(1)) + cond_ = p[3] + + p[0] = label_, cond_ + + +def p_elseif_list(p): + """ elseiflist : elseif_expr program_co endif + | elseif_expr program_co else_part + """ + label_, cond_ = p[1] + then_ = p[2] + else_ = p[3] - if isinstance(p5, list): # it's an else part - p5 = make_block(*p5) + if isinstance(else_, list): # it's an else part + else_ = make_block(*else_) else: - p4 = make_block(p4, p5) - p5 = None + then_ = make_block(then_, else_) + else_ = None - if is_null(p4): + if is_null(then_): warning(p.lineno(1), 'Useless empty ELSEIF ignored') - p[0] = make_block(p1, p5) + p[0] = make_block(label_, else_) return - if is_number(p2): - api.errmsg.warning_condition_is_always(p.lineno(1), bool(p2.value)) + if is_number(cond_): + api.errmsg.warning_condition_is_always(p.lineno(1), bool(cond_.value)) if OPTIONS.optimization.value > 0: - if not p2.value: - p[0] = make_block(p1, p5) + if not cond_.value: + p[0] = make_block(label_, else_) return - p[0] = make_block(p1, make_sentence('IF', p2, p4, p5)) + p[0] = make_block(label_, make_sentence('IF', cond_, then_, else_, lineno=p.lineno(1))) def p_elseif_elseiflist(p): - """ elseiflist : ELSEIF expr then program_co elseiflist - | LABEL ELSEIF expr then program_co elseiflist + """ elseiflist : elseif_expr program_co elseiflist """ - if p[1] == 'ELSEIF': - p1 = make_nop() - p2 = p[2] - p4 = p[4] - p5 = p[5] - else: - p1 = make_label(p[1], p.lineno(1)) - p2 = p[3] - p4 = p[5] - p5 = p[6] + label_, cond_ = p[1] + then_ = p[2] + else_ = p[3] - if is_null(p4, p5): - p[0] = make_block(p1, p5) + if is_null(then_, else_): + p[0] = make_block(label_, else_) return - if is_number(p2) and p2.value == 0: + if is_number(cond_) and cond_.value == 0: api.errmsg.warning_condition_is_always(p.lineno(1)) if OPTIONS.optimization.value > 0: - p[0] = make_block(p1, p5) + p[0] = make_block(label_, else_) return - p[0] = make_block(p1, make_sentence('IF', p2, p4, p5)) + p[0] = make_block(label_, make_sentence('IF', cond_, then_, else_)) def p_else_part_endif(p): From 76c7aebc89b80dae85d49a256ec5bbd4e9673777 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 22 Nov 2017 00:47:54 +0100 Subject: [PATCH 125/247] Better code generation Now the optimizer centralizes al IF optimization. Also allows now empty ELSE after ELSEIF --- api/check.py | 6 ++- api/optimize.py | 17 ++++++-- arch/zx48k/translator.py | 2 +- tests/functional/elseif6.asm | 6 +-- tests/functional/ifelse1.asm | 10 ++--- tests/functional/ifemptyprogelse.asm | 37 ++++++++++++++++ tests/functional/ifemptyprogelse.bas | 8 ++++ zxbparser.py | 63 ++++------------------------ 8 files changed, 78 insertions(+), 71 deletions(-) create mode 100644 tests/functional/ifemptyprogelse.asm create mode 100644 tests/functional/ifemptyprogelse.bas diff --git a/api/check.py b/api/check.py index 17397c06a..7ed944445 100644 --- a/api/check.py +++ b/api/check.py @@ -203,7 +203,7 @@ def check_and_make_label(lbl, lineno): # ---------------------------------------------------------------------- def is_null(*symbols): """ True if no nodes or all the given nodes are either - None, NOP or empty blocks. + None, NOP or empty blocks. For blocks this applies recursively """ from symbols.symbol_ import Symbol @@ -214,7 +214,9 @@ def is_null(*symbols): return False if sym.token == 'NOP': continue - if sym.token == 'BLOCK' and not sym: + if sym.token == 'BLOCK': + if not is_null(*sym.children): + return False continue return False return True diff --git a/api/optimize.py b/api/optimize.py index b6a5fee2b..32ccfb7da 100644 --- a/api/optimize.py +++ b/api/optimize.py @@ -25,7 +25,7 @@ def __init__(self, obj): class OptimizerVisitor(NodeVisitor): """ Implements some optimizations """ - NOP = symbols.SENTENCE('NOP') # Return this for "erased" nodes + NOP = symbols.NOP() # Return this for "erased" nodes @staticmethod def TYPE(type_): @@ -157,11 +157,17 @@ def visit_UNARY(self, node): else: yield (yield self.generic_visit(node)) + def visit_BLOCK(self, node): + if self.O_LEVEL >= 1 and chk.is_null(node): + yield self.NOP + return + yield (yield self.generic_visit(node)) + def visit_IF(self, node): if self.O_LEVEL >= 1: expr_ = node.children[0] - then_ = node.children[1] - else_ = node.children[2] if len(node.children) == 3 else self.NOP + then_ = (yield ToVisit(node.children[1])) + else_ = (yield ToVisit(node.children[2])) if len(node.children) == 3 else self.NOP if chk.is_null(then_, else_): api.errmsg.warning_empty_if(node.lineno) @@ -176,6 +182,11 @@ def visit_IF(self, node): yield else_ return + if chk.is_null(else_) and len(node.children) == 3: + node.children.pop() # remove empty else + yield node + return + yield (yield self.generic_visit(node)) # TODO: ignore unused labels diff --git a/arch/zx48k/translator.py b/arch/zx48k/translator.py index 838269e53..f8e868729 100644 --- a/arch/zx48k/translator.py +++ b/arch/zx48k/translator.py @@ -824,7 +824,7 @@ def visit_CHKBREAK(self, node): backend.REQUIRES.add('break.asm') def visit_IF(self, node): - assert 1 < len(node.children) < 4 + assert 1 < len(node.children) < 4, 'IF nodes: %i' % len(node.children) yield node.children[0] if_label_else = backend.tmp_label() if_label_endif = backend.tmp_label() diff --git a/tests/functional/elseif6.asm b/tests/functional/elseif6.asm index 39dacd128..667da2109 100644 --- a/tests/functional/elseif6.asm +++ b/tests/functional/elseif6.asm @@ -14,12 +14,10 @@ __START_PROGRAM: ld a, (_a) call __LTI8 or a - jp z, __LABEL0 + jp z, __LABEL1 ld a, (_a) inc a ld (_a), a - jp __LABEL1 -__LABEL0: __LABEL1: ld hl, 0 ld b, h @@ -63,7 +61,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 29 "elseif6.bas" +#line 27 "elseif6.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/ifelse1.asm b/tests/functional/ifelse1.asm index f4b2ea7e2..367eeb448 100644 --- a/tests/functional/ifelse1.asm +++ b/tests/functional/ifelse1.asm @@ -16,10 +16,8 @@ __START_PROGRAM: call __PRINT_INIT ld a, (_a) sub 2 - sub 1 - sbc a, a - or a - jp nz, __LABEL1 + jp z, __LABEL1 +__LABEL0: ld hl, __LABEL2 xor a call __PRINTSTR @@ -1178,7 +1176,7 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ENDP -#line 44 "ifelse1.bas" +#line 42 "ifelse1.bas" #line 1 "printstr.asm" @@ -1555,7 +1553,7 @@ __PRINT_STR: ENDP -#line 45 "ifelse1.bas" +#line 43 "ifelse1.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/ifemptyprogelse.asm b/tests/functional/ifemptyprogelse.asm new file mode 100644 index 000000000..237c470ee --- /dev/null +++ b/tests/functional/ifemptyprogelse.asm @@ -0,0 +1,37 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifemptyprogelse.bas b/tests/functional/ifemptyprogelse.bas new file mode 100644 index 000000000..740bc0f70 --- /dev/null +++ b/tests/functional/ifemptyprogelse.bas @@ -0,0 +1,8 @@ + +DIM a as Byte + +if a < 0 then +elseif a > 0 then +else +end if + diff --git a/zxbparser.py b/zxbparser.py index 629512cc3..732208369 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -1209,21 +1209,7 @@ def p_if_elseif(p): cond_ = p[1] stats_ = p[3] if len(p) == 5 else make_nop() eliflist = p[4] if len(p) == 5 else p[3] - if is_null(stats_, eliflist): - p[0] = make_nop() - return - - if is_number(p[2]): - api.errmsg.warning_condition_is_always(p.lineno(1), bool(p[2].value)) - if OPTIONS.optimization.value > 0: - if not p[2].value: - p[0] = eliflist - return - else: - p[0] = stats_ - return - - p[0] = make_sentence('IF', cond_, stats_, eliflist) + p[0] = make_sentence('IF', cond_, stats_, eliflist, lineno=p.lineno(2)) def p_elseif_part(p): @@ -1254,18 +1240,6 @@ def p_elseif_list(p): then_ = make_block(then_, else_) else_ = None - if is_null(then_): - warning(p.lineno(1), 'Useless empty ELSEIF ignored') - p[0] = make_block(label_, else_) - return - - if is_number(cond_): - api.errmsg.warning_condition_is_always(p.lineno(1), bool(cond_.value)) - if OPTIONS.optimization.value > 0: - if not cond_.value: - p[0] = make_block(label_, else_) - return - p[0] = make_block(label_, make_sentence('IF', cond_, then_, else_, lineno=p.lineno(1))) @@ -1275,26 +1249,19 @@ def p_elseif_elseiflist(p): label_, cond_ = p[1] then_ = p[2] else_ = p[3] - - if is_null(then_, else_): - p[0] = make_block(label_, else_) - return - - if is_number(cond_) and cond_.value == 0: - api.errmsg.warning_condition_is_always(p.lineno(1)) - if OPTIONS.optimization.value > 0: - p[0] = make_block(label_, else_) - return - - p[0] = make_block(label_, make_sentence('IF', cond_, then_, else_)) + p[0] = make_block(label_, make_sentence('IF', cond_, then_, else_, lineno=p.lineno(1))) def p_else_part_endif(p): """ else_part_inline : ELSE NEWLINE program_co endif + | ELSE NEWLINE endif | ELSE statements_co endif | ELSE co_statements_co endif """ - p[0] = [p[2], p[3]] if len(p) == 4 else [p[3], p[4]] + if p[2] == '\n': + p[0] = [make_nop(), p[3]] if len(p) == 4 else [p[3], p[4]] + else: + p[0] = [p[2], p[3]] def p_else_part(p): @@ -1343,21 +1310,7 @@ def p_if_else(p): then_ = p[3] else_ = p[4][0] endif = p[4][1] - - if is_null(then_, else_): - api.errmsg.warning_empty_if(p.lineno(2)) - p[0] = endif - return - - if is_null(then_): - cond_ = make_unary(p.lineno(1), 'NOT', cond_, lambda x: not x) - p[0] = make_sentence('IF', cond_, make_block(else_, endif)) - return - - if is_null(else_): - else_ = None - - p[0] = make_sentence('IF', cond_, then_, make_block(else_, endif)) + p[0] = make_sentence('IF', cond_, then_, make_block(else_, endif), lineno=p.lineno(2)) def p_then(p): From 934f6a039bd7a6e93327a1656463a111fd26812c Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Thu, 23 Nov 2017 00:05:58 +0100 Subject: [PATCH 126/247] bugfix: WHILE optimization While optimization must not remove empty WHILE statements if the condition is always true. The infinite loop might be intended by the user. Also, when removing a WHILE sentence (always false), it must be checked the body is not accessed with a GOTO or the like. --- api/optimize.py | 11 +++++++- tests/functional/whilefalse.asm | 37 +++++++++++++++++++++++++ tests/functional/whilefalse.bas | 5 ++++ tests/functional/whilefalse1.asm | 46 ++++++++++++++++++++++++++++++++ tests/functional/whilefalse1.bas | 7 +++++ tests/functional/whiletrue.asm | 43 +++++++++++++++++++++++++++++ tests/functional/whiletrue.bas | 5 ++++ zxbparser.py | 23 ++++++---------- 8 files changed, 161 insertions(+), 16 deletions(-) create mode 100644 tests/functional/whilefalse.asm create mode 100644 tests/functional/whilefalse.bas create mode 100644 tests/functional/whilefalse1.asm create mode 100644 tests/functional/whilefalse1.bas create mode 100644 tests/functional/whiletrue.asm create mode 100644 tests/functional/whiletrue.bas diff --git a/api/optimize.py b/api/optimize.py index 32ccfb7da..68cff87c3 100644 --- a/api/optimize.py +++ b/api/optimize.py @@ -165,7 +165,7 @@ def visit_BLOCK(self, node): def visit_IF(self, node): if self.O_LEVEL >= 1: - expr_ = node.children[0] + expr_ = (yield ToVisit(node.children[0])) then_ = (yield ToVisit(node.children[1])) else_ = (yield ToVisit(node.children[2])) if len(node.children) == 3 else self.NOP @@ -189,6 +189,15 @@ def visit_IF(self, node): yield (yield self.generic_visit(node)) + def visit_WHILE(self, node): + if self.O_LEVEL >= 1: + expr_ = (yield node.children[0]) + body_ = (yield node.children[1]) + if chk.is_number(expr_) and not expr_.value and not chk.is_block_accessed(body_): + yield self.NOP + return + yield (yield self.generic_visit(node)) + # TODO: ignore unused labels def _visit_LABEL(self, node): if self.O_LEVEL and not node.accessed: diff --git a/tests/functional/whilefalse.asm b/tests/functional/whilefalse.asm new file mode 100644 index 000000000..237c470ee --- /dev/null +++ b/tests/functional/whilefalse.asm @@ -0,0 +1,37 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/whilefalse.bas b/tests/functional/whilefalse.bas new file mode 100644 index 000000000..1c44967d0 --- /dev/null +++ b/tests/functional/whilefalse.bas @@ -0,0 +1,5 @@ +DIM a as Byte +WHILE 0 + a = a + 1 +WEND + diff --git a/tests/functional/whilefalse1.asm b/tests/functional/whilefalse1.asm new file mode 100644 index 000000000..bed5b7fc7 --- /dev/null +++ b/tests/functional/whilefalse1.asm @@ -0,0 +1,46 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei +__LABEL0: + jp __LABEL1 +__LABEL__BAD: + ld a, (_a) + inc a + ld (_a), a + jp __LABEL0 +__LABEL1: + jp __LABEL__BAD + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/whilefalse1.bas b/tests/functional/whilefalse1.bas new file mode 100644 index 000000000..ddb6d63e8 --- /dev/null +++ b/tests/functional/whilefalse1.bas @@ -0,0 +1,7 @@ +DIM a as Byte +WHILE 0 +BAD: + a = a + 1 +WEND +GOTO BAD + diff --git a/tests/functional/whiletrue.asm b/tests/functional/whiletrue.asm new file mode 100644 index 000000000..4a34e96b0 --- /dev/null +++ b/tests/functional/whiletrue.asm @@ -0,0 +1,43 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei +__LABEL0: + ld a, (_a) + inc a + ld (_a), a + jp __LABEL0 +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/whiletrue.bas b/tests/functional/whiletrue.bas new file mode 100644 index 000000000..da05157d9 --- /dev/null +++ b/tests/functional/whiletrue.bas @@ -0,0 +1,5 @@ +DIM a as Byte +WHILE 1 + a = a + 1 +WEND + diff --git a/zxbparser.py b/zxbparser.py index 732208369..0128e6cc9 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -1687,22 +1687,13 @@ def p_while_sentence(p): gl.LOOPS.pop() q = make_block(p[2], p[3]) - if is_number(p[1]): - if p[1].value == 0: - api.errmsg.warning_condition_is_always(p[1].lineno) - if OPTIONS.optimization.value > 0: - warning(p[1].lineno, "Loop has been ignored") - p[0] = None - else: - p[0] = make_sentence('WHILE', p[1], q) + if is_number(p[1]) and p[1].value: + if q is None: + warning(p[1].lineno, "Condition is always true and leads to an infinite loop.") else: - p[0] = make_sentence('WHILE', p[1], q) - if q is None: - warning(p[1].lineno, "Condition is always true and leads to an infinite loop.") - else: - warning(p[1].lineno, "Condition is always true and might lead to an infinite loop.") - else: - p[0] = make_sentence('WHILE', p[1], q) + warning(p[1].lineno, "Condition is always true and might lead to an infinite loop.") + + p[0] = make_sentence('WHILE', p[1], q) def p_while_start(p): @@ -1710,6 +1701,8 @@ def p_while_start(p): """ p[0] = p[2] gl.LOOPS.append(('WHILE',)) + if is_number(p[2]) and not p[2].value: + api.errmsg.warning_condition_is_always(p.lineno(1)) def p_exit(p): From 7d9aab2e7262b603d52b7d2410eeff322ff7dfc1 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 24 Nov 2017 22:18:11 +0100 Subject: [PATCH 127/247] bugfix: prevent FOR optmization on accessed blocks When a FOR loop is skipped (not executed because its limits are wrong), do not remove its block if it's being accessed from the inside. --- api/optimize.py | 15 +++++++ tests/functional/forempty.asm | 77 ++++++++++++++++++++++++++++++++ tests/functional/forempty.bas | 5 +++ tests/functional/fornextopt.asm | 56 +++++++++++++++++++++++ tests/functional/fornextopt.bas | 9 ++++ tests/functional/fornextopt2.asm | 56 +++++++++++++++++++++++ tests/functional/fornextopt2.bas | 9 ++++ tests/functional/fornextopt3.asm | 37 +++++++++++++++ tests/functional/fornextopt3.bas | 8 ++++ tests/functional/fornextopt4.asm | 37 +++++++++++++++ tests/functional/fornextopt4.bas | 8 ++++ tests/functional/test_errmsg.txt | 6 +++ zxbparser.py | 8 +--- 13 files changed, 324 insertions(+), 7 deletions(-) create mode 100644 tests/functional/forempty.asm create mode 100644 tests/functional/forempty.bas create mode 100644 tests/functional/fornextopt.asm create mode 100644 tests/functional/fornextopt.bas create mode 100644 tests/functional/fornextopt2.asm create mode 100644 tests/functional/fornextopt2.bas create mode 100644 tests/functional/fornextopt3.asm create mode 100644 tests/functional/fornextopt3.bas create mode 100644 tests/functional/fornextopt4.asm create mode 100644 tests/functional/fornextopt4.bas diff --git a/api/optimize.py b/api/optimize.py index 68cff87c3..fee5e8476 100644 --- a/api/optimize.py +++ b/api/optimize.py @@ -198,6 +198,21 @@ def visit_WHILE(self, node): return yield (yield self.generic_visit(node)) + def visit_FOR(self, node): + from_ = node.children[1] + to_ = node.children[2] + step_ = node.children[3] + body_ = node.children[4] + + if self.O_LEVEL > 0 and chk.is_number(from_, to_, step_) and not chk.is_block_accessed(body_): + if from_ > to_ and step_ > 0: + yield self.NOP + return + if from_ < to_ and step_ < 0: + yield self.NOP + return + yield (yield self.generic_visit(node)) + # TODO: ignore unused labels def _visit_LABEL(self, node): if self.O_LEVEL and not node.accessed: diff --git a/tests/functional/forempty.asm b/tests/functional/forempty.asm new file mode 100644 index 000000000..75d67897c --- /dev/null +++ b/tests/functional/forempty.asm @@ -0,0 +1,77 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + xor a + ld (_a), a + jp __LABEL0 +__LABEL3: +__LABEL4: + ld a, (_a) +__LABEL0: + ld a, 1 + ld hl, (_a - 1) + call __LTI8 + or a + jp z, __LABEL3 +__LABEL2: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "lti8.asm" + +#line 1 "lei8.asm" + +__LEI8: ; Signed <= comparison for 8bit int + ; A <= H (registers) + PROC + LOCAL checkParity + sub h + jr nz, __LTI + inc a + ret + +__LTI8: ; Test 8 bit values A < H + sub h + +__LTI: ; Generic signed comparison + jp po, checkParity + xor 0x80 +checkParity: + ld a, 0 ; False + ret p + inc a ; True + ret + ENDP +#line 2 "lti8.asm" +#line 31 "forempty.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/forempty.bas b/tests/functional/forempty.bas new file mode 100644 index 000000000..311e4967c --- /dev/null +++ b/tests/functional/forempty.bas @@ -0,0 +1,5 @@ + +DIM a as Byte + +FOR a = 0 TO 1 STEP 0: NEXT + diff --git a/tests/functional/fornextopt.asm b/tests/functional/fornextopt.asm new file mode 100644 index 000000000..6a28e83e5 --- /dev/null +++ b/tests/functional/fornextopt.asm @@ -0,0 +1,56 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld a, 1 + ld (_a), a + jp __LABEL0 +__LABEL3: +__LABEL__lbl: + ld a, (_a) + inc a + ld (_a), a +__LABEL4: + ld a, (_a) + inc a + ld (_a), a +__LABEL0: + xor a + ld hl, (_a - 1) + cp h + jp nc, __LABEL3 +__LABEL2: + jp __LABEL__lbl + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/fornextopt.bas b/tests/functional/fornextopt.bas new file mode 100644 index 000000000..c355ed89f --- /dev/null +++ b/tests/functional/fornextopt.bas @@ -0,0 +1,9 @@ + +DIM a as UByte + +FOR a = 1 TO 0 +lbl: +a = a + 1 +NEXT a + +GOTO lbl diff --git a/tests/functional/fornextopt2.asm b/tests/functional/fornextopt2.asm new file mode 100644 index 000000000..da7bab325 --- /dev/null +++ b/tests/functional/fornextopt2.asm @@ -0,0 +1,56 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld a, 10 + ld (_a), a + jp __LABEL0 +__LABEL3: +__LABEL__lbl: + ld a, (_a) + inc a + ld (_a), a +__LABEL4: + ld a, (_a) + dec a + ld (_a), a +__LABEL0: + ld h, 11 + ld a, (_a) + cp h + jp nc, __LABEL3 +__LABEL2: + jp __LABEL__lbl + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/fornextopt2.bas b/tests/functional/fornextopt2.bas new file mode 100644 index 000000000..c1a9c963b --- /dev/null +++ b/tests/functional/fornextopt2.bas @@ -0,0 +1,9 @@ + +DIM a as UByte + +FOR a = 10 TO 11 STEP -1 +lbl: +a = a + 1 +NEXT a + +GOTO lbl diff --git a/tests/functional/fornextopt3.asm b/tests/functional/fornextopt3.asm new file mode 100644 index 000000000..237c470ee --- /dev/null +++ b/tests/functional/fornextopt3.asm @@ -0,0 +1,37 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/fornextopt3.bas b/tests/functional/fornextopt3.bas new file mode 100644 index 000000000..e5af8ec85 --- /dev/null +++ b/tests/functional/fornextopt3.bas @@ -0,0 +1,8 @@ + +DIM a as UByte + +FOR a = 1 TO 0 +lbl: +a = a + 1 +NEXT a + diff --git a/tests/functional/fornextopt4.asm b/tests/functional/fornextopt4.asm new file mode 100644 index 000000000..237c470ee --- /dev/null +++ b/tests/functional/fornextopt4.asm @@ -0,0 +1,37 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/fornextopt4.bas b/tests/functional/fornextopt4.bas new file mode 100644 index 000000000..72ad68be3 --- /dev/null +++ b/tests/functional/fornextopt4.bas @@ -0,0 +1,8 @@ + +DIM a as UByte + +FOR a = 10 TO 11 STEP -1 +lbl: +a = a + 1 +NEXT a + diff --git a/tests/functional/test_errmsg.txt b/tests/functional/test_errmsg.txt index 5306846b9..20ccea4e4 100644 --- a/tests/functional/test_errmsg.txt +++ b/tests/functional/test_errmsg.txt @@ -102,4 +102,10 @@ ifempty1.bas:3: warning: Useless empty IF ignored ifempty5.bas:3: warning: Condition is always True >>> process_file('ifempty0.bas') ifempty0.bas:3: warning: Useless empty IF ignored +>>> process_file('forempty.bas') +forempty.bas:4: warning: STEP value is 0 and FOR might loop forever +>>> process_file('fornextopt.bas') +fornextopt.bas:4: warning: FOR start value is greater than end. This FOR loop is useless +>>> process_file('fornextopt2.bas') +fornextopt2.bas:4: warning: FOR start value is lower than end. This FOR loop is useless diff --git a/zxbparser.py b/zxbparser.py index 0128e6cc9..27d944aad 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -1361,29 +1361,23 @@ def p_next1(p): def p_for_sentence_start(p): """ for_start : FOR ID EQ expr TO expr step """ - # api.check.check_is_declared(p.lineno(2), p[2]) gl.LOOPS.append(('FOR', p[2])) p[0] = None if p[4] is None or p[6] is None or p[7] is None: return - if is_number([p[4], p[6], p[7]]): + if is_number(p[4], p[6], p[7]): if p[4].value != p[6].value and p[7].value == 0: warning(p.lineno(5), 'STEP value is 0 and FOR might loop forever') if p[4].value > p[6].value and p[7].value > 0: warning(p.lineno(5), 'FOR start value is greater than end. This FOR loop is useless') - if OPTIONS.optimizations > 0: - return if p[4].value < p[6].value and p[7].value < 0: warning(p.lineno(2), 'FOR start value is lower than end. This FOR loop is useless') - if OPTIONS.optimizations > 0: - return id_type = common_type(common_type(p[4], p[6]), p[7]) - variable = SYMBOL_TABLE.access_var(p[2], p.lineno(2), default_type=id_type) if variable is None: return From 22dc7d3567519788ffa5ee3330055ede2ef86c47 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Thu, 23 Nov 2017 11:11:04 +0100 Subject: [PATCH 128/247] refact: BLOCK symbol * Uses super() in the init() * Recursively optimizes nested blocks, flattening them --- symbols/block.py | 4 ++-- tests/symbols/test_symbolBLOCK.py | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/symbols/block.py b/symbols/block.py index c21e2ab89..35fa6d4b6 100644 --- a/symbols/block.py +++ b/symbols/block.py @@ -17,7 +17,7 @@ class SymbolBLOCK(Symbol): """ Defines a block of code. """ def __init__(self, *nodes): - Symbol.__init__(self, *(x for x in nodes if not is_null(x))) + super(SymbolBLOCK, self).__init__(*(x for x in nodes if not is_null(x))) @classmethod def make_node(cls, *args): @@ -29,7 +29,7 @@ def make_node(cls, *args): for x in args: assert isinstance(x, Symbol) if x.token == 'BLOCK': - new_args.extend(x.children) + new_args.extend(SymbolBLOCK.make_node(*x.children).children) else: new_args.append(x) diff --git a/tests/symbols/test_symbolBLOCK.py b/tests/symbols/test_symbolBLOCK.py index 82a7d9858..004f1ae77 100644 --- a/tests/symbols/test_symbolBLOCK.py +++ b/tests/symbols/test_symbolBLOCK.py @@ -48,6 +48,12 @@ def test_make_node_optimize2(self): for x in b: self.assertIsInstance(x, NUMBER) + def test_make_node_optimize3(self): + n = NUMBER(1, lineno=1) + b = BLOCK.make_node(BLOCK(BLOCK(BLOCK())), BLOCK(BLOCK(n), BLOCK(BLOCK()))) + self.assertEqual(len(b), 1) + self.assertEqual(b, BLOCK(n)) + def test__eq__(self): b = BLOCK() self.assertEqual(b, b) From 192b4a91383b0e835de7b7f9542f33a08a9cc905 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 27 Nov 2017 00:11:03 +0100 Subject: [PATCH 129/247] feature: mimic FreeBasic IF This update forces END IF if a colon if used after THEN: or ELSE: --- tests/functional/ifempty0.asm | 37 -------------- tests/functional/ifthencoendif.asm | 73 +++++++++++++++++++++++++++ tests/functional/ifthencoendif.bas | 7 +++ tests/functional/ifthencoendif2.asm | 78 +++++++++++++++++++++++++++++ tests/functional/ifthencoendif2.bas | 9 ++++ tests/functional/test_errmsg.txt | 2 +- zxbparser.py | 5 +- 7 files changed, 172 insertions(+), 39 deletions(-) delete mode 100644 tests/functional/ifempty0.asm create mode 100644 tests/functional/ifthencoendif.asm create mode 100644 tests/functional/ifthencoendif.bas create mode 100644 tests/functional/ifthencoendif2.asm create mode 100644 tests/functional/ifthencoendif2.bas diff --git a/tests/functional/ifempty0.asm b/tests/functional/ifempty0.asm deleted file mode 100644 index 49d4ccd19..000000000 --- a/tests/functional/ifempty0.asm +++ /dev/null @@ -1,37 +0,0 @@ - org 32768 -__START_PROGRAM: - di - push ix - push iy - exx - push hl - exx - ld hl, 0 - add hl, sp - ld (__CALL_BACK__), hl - ei - ld hl, 0 - ld b, h - ld c, l -__END_PROGRAM: - di - ld hl, (__CALL_BACK__) - ld sp, hl - exx - pop hl - exx - pop iy - pop ix - ei - ret -__CALL_BACK__: - DEFW 0 - -ZXBASIC_USER_DATA: -_i: - DEFB 00 - ; Defines DATA END --> HEAP size is 0 -ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP - ; Defines USER DATA Length in bytes -ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA - END diff --git a/tests/functional/ifthencoendif.asm b/tests/functional/ifthencoendif.asm new file mode 100644 index 000000000..c95c9230a --- /dev/null +++ b/tests/functional/ifthencoendif.asm @@ -0,0 +1,73 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld h, 0 + ld a, (_a) + call __LTI8 + or a + jp z, __LABEL1 + ld a, (_a) + inc a + ld (_a), a +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "lti8.asm" + +#line 1 "lei8.asm" + +__LEI8: ; Signed <= comparison for 8bit int + ; A <= H (registers) + PROC + LOCAL checkParity + sub h + jr nz, __LTI + inc a + ret + +__LTI8: ; Test 8 bit values A < H + sub h + +__LTI: ; Generic signed comparison + jp po, checkParity + xor 0x80 +checkParity: + ld a, 0 ; False + ret p + inc a ; True + ret + ENDP +#line 2 "lti8.asm" +#line 27 "ifthencoendif.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifthencoendif.bas b/tests/functional/ifthencoendif.bas new file mode 100644 index 000000000..4ecd06571 --- /dev/null +++ b/tests/functional/ifthencoendif.bas @@ -0,0 +1,7 @@ + +DIM a as Byte + +IF a < 0 THEN: + LET a = a + 1 +END IF + diff --git a/tests/functional/ifthencoendif2.asm b/tests/functional/ifthencoendif2.asm new file mode 100644 index 000000000..34cde75ad --- /dev/null +++ b/tests/functional/ifthencoendif2.asm @@ -0,0 +1,78 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld h, 0 + ld a, (_a) + call __LTI8 + or a + jp z, __LABEL0 + ld a, (_a) + inc a + ld (_a), a + jp __LABEL1 +__LABEL0: + ld a, (_a) + dec a + ld (_a), a +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "lti8.asm" + +#line 1 "lei8.asm" + +__LEI8: ; Signed <= comparison for 8bit int + ; A <= H (registers) + PROC + LOCAL checkParity + sub h + jr nz, __LTI + inc a + ret + +__LTI8: ; Test 8 bit values A < H + sub h + +__LTI: ; Generic signed comparison + jp po, checkParity + xor 0x80 +checkParity: + ld a, 0 ; False + ret p + inc a ; True + ret + ENDP +#line 2 "lti8.asm" +#line 32 "ifthencoendif2.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifthencoendif2.bas b/tests/functional/ifthencoendif2.bas new file mode 100644 index 000000000..902b6673b --- /dev/null +++ b/tests/functional/ifthencoendif2.bas @@ -0,0 +1,9 @@ + +DIM a as Byte + +IF a < 0 THEN: + LET a = a + 1 +ELSE: + LET a = a - 1 +END IF + diff --git a/tests/functional/test_errmsg.txt b/tests/functional/test_errmsg.txt index 20ccea4e4..08d953590 100644 --- a/tests/functional/test_errmsg.txt +++ b/tests/functional/test_errmsg.txt @@ -101,7 +101,7 @@ ifempty1.bas:3: warning: Useless empty IF ignored >>> process_file('ifempty5.bas') ifempty5.bas:3: warning: Condition is always True >>> process_file('ifempty0.bas') -ifempty0.bas:3: warning: Useless empty IF ignored +ifempty0.bas:5: Unexpected end of file >>> process_file('forempty.bas') forempty.bas:4: warning: STEP value is 0 and FOR might loop forever >>> process_file('fornextopt.bas') diff --git a/zxbparser.py b/zxbparser.py index 27d944aad..7d96fa84a 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -1156,6 +1156,7 @@ def p_go(p): # region [IF sentence] def p_if_sentence(p): """ statement : if_then_part NEWLINE program_co endif + | if_then_part CO program_co endif | if_then_part NEWLINE endif """ cond_ = p[1] @@ -1254,11 +1255,12 @@ def p_elseif_elseiflist(p): def p_else_part_endif(p): """ else_part_inline : ELSE NEWLINE program_co endif + | ELSE CO program_co endif | ELSE NEWLINE endif | ELSE statements_co endif | ELSE co_statements_co endif """ - if p[2] == '\n': + if p[2] in ('\n', ':'): p[0] = [make_nop(), p[3]] if len(p) == 4 else [p[3], p[4]] else: p[0] = [p[2], p[3]] @@ -1305,6 +1307,7 @@ def p_if_inline(p): def p_if_else(p): """ statement : if_then_part NEWLINE program_co else_part + | if_then_part CO program_co else_part """ cond_ = p[1] then_ = p[3] From 9b0643180e3d40c3120a8c6d69f2b4917e43ad82 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 28 Nov 2017 22:17:05 +0100 Subject: [PATCH 130/247] bugfix: prevent infinite recursion in traversal When doing optimizations, functions must be avoided when being called (they are checked later) to avoid crash due to infinite loop. --- api/check.py | 10 +- tests/functional/fact.asm | 2158 ++++++++++++++++++++++++++++++++++ tests/functional/fact.bas | 15 + tests/functional/subrec.asm | 2174 +++++++++++++++++++++++++++++++++++ tests/functional/subrec.bas | 20 + 5 files changed, 4376 insertions(+), 1 deletion(-) create mode 100644 tests/functional/fact.asm create mode 100644 tests/functional/fact.bas create mode 100644 tests/functional/subrec.asm create mode 100644 tests/functional/subrec.bas diff --git a/api/check.py b/api/check.py index 7ed944445..b3a009091 100644 --- a/api/check.py +++ b/api/check.py @@ -16,6 +16,7 @@ import api.errmsg from .errmsg import syntax_error + __all__ = ['check_type', 'check_is_declared_explicit', 'check_type_is_explicit', @@ -387,6 +388,13 @@ def is_dynamic(*p): # TODO: Explain this better return False +def is_callable(*p): + """ True if all the args are functions and / or subroutines + """ + import symbols + return all(isinstance(x, symbols.FUNCTION) for x in p) + + def is_block_accessed(block): """ Returns True if a block is "accessed". A block of code is accessed if it has a LABEL and it is used in a GOTO, GO SUB or @address access @@ -397,7 +405,7 @@ def is_block_accessed(block): return True for child in block.children: - if is_block_accessed(child): + if not is_callable(child) and is_block_accessed(child): return True return False diff --git a/tests/functional/fact.asm b/tests/functional/fact.asm new file mode 100644 index 000000000..d16204a24 --- /dev/null +++ b/tests/functional/fact.asm @@ -0,0 +1,2158 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + call __PRINT_INIT + call CLS + ld a, 1 + ld (_x), a + jp __LABEL0 +__LABEL3: + ld hl, __LABEL5 + xor a + call __PRINTSTR + ld a, (_x) + call __PRINTU8 + ld hl, __LABEL6 + xor a + call __PRINTSTR + ld a, (_x) + ld l, a + ld h, 0 + ld e, h + ld d, h + push de + push hl + call _fact + call __PRINTU32 + call PRINT_EOL +__LABEL4: + ld a, (_x) + inc a + ld (_x), a +__LABEL0: + ld a, 10 + ld hl, (_x - 1) + cp h + jp nc, __LABEL3 +__LABEL2: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +_fact: + push ix + ld ix, 0 + add ix, sp + ld l, (ix+4) + ld h, (ix+5) + ld e, (ix+6) + ld d, (ix+7) + push de + push hl + ld de, 0 + ld hl, 2 + call __SUB32 + jp nc, __LABEL8 + ld de, 0 + ld hl, 1 + jp _fact__leave +__LABEL8: + ld l, (ix+4) + ld h, (ix+5) + ld e, (ix+6) + ld d, (ix+7) + push de + push hl + ld l, (ix+4) + ld h, (ix+5) + ld e, (ix+6) + ld d, (ix+7) + push de + push hl + ld de, 0 + ld hl, 1 + call __SUB32 + push de + push hl + call _fact + call __MUL32 +_fact__leave: + ld sp, ix + pop ix + exx + pop hl + pop bc + ex (sp), hl + exx + ret +__LABEL5: + DEFW 0006h + DEFB 46h + DEFB 61h + DEFB 63h + DEFB 74h + DEFB 20h + DEFB 28h +__LABEL6: + DEFW 0004h + DEFB 29h + DEFB 20h + DEFB 3Dh + DEFB 20h +#line 1 "cls.asm" + + ; JUMPS directly to spectrum CLS + ; This routine does not clear lower screen + + ;CLS EQU 0DAFh + + ; Our faster implementation + +#line 1 "sposn.asm" + + ; Printing positioning library. + PROC + LOCAL ECHO_E + +__LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. + ld de, (S_POSN) + ld hl, (MAXX) + or a + sbc hl, de + ex de, hl + ret + + +__SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. + ld hl, (MAXX) + or a + sbc hl, de + ld (S_POSN), hl ; saves it again + ret + + + ECHO_E EQU 23682 + MAXX EQU ECHO_E ; Max X position + 1 + MAXY EQU MAXX + 1 ; Max Y position + 1 + + S_POSN EQU 23688 + POSX EQU S_POSN ; Current POS X + POSY EQU S_POSN + 1 ; Current POS Y + + ENDP + +#line 9 "cls.asm" + +CLS: + PROC + + LOCAL COORDS + LOCAL __CLS_SCR + LOCAL ATTR_P + LOCAL SCREEN + + ld hl, 0 + ld (COORDS), hl + ld hl, 1821h + ld (S_POSN), hl +__CLS_SCR: + ld hl, SCREEN + ld (hl), 0 + ld d, h + ld e, l + inc de + ld bc, 6144 + ldir + + ; Now clear attributes + + ld a, (ATTR_P) + ld (hl), a + ld bc, 767 + ldir + ret + + COORDS EQU 23677 + SCREEN EQU 16384 ; Default start of the screen (can be changed) + ATTR_P EQU 23693 + ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address + + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines + ; to get the start of the screen + ENDP + +#line 111 "fact.bas" +#line 1 "mul32.asm" + +#line 1 "_mul32.asm" + + +; Ripped from: http://www.andreadrian.de/oldcpu/z80_number_cruncher.html#moztocid784223 + ; Used with permission. + ; Multiplies 32x32 bit integer (DEHL x D'E'H'L') + ; 64bit result is returned in H'L'H L B'C'A C + + +__MUL32_64START: + push hl + exx + ld b, h + ld c, l ; BC = Low Part (A) + pop hl ; HL = Load Part (B) + ex de, hl ; DE = Low Part (B), HL = HightPart(A) (must be in B'C') + push hl + + exx + pop bc ; B'C' = HightPart(A) + exx ; A = B'C'BC , B = D'E'DE + + ; multiply routine 32 * 32bit = 64bit + ; h'l'hlb'c'ac = b'c'bc * d'e'de + ; needs register a, changes flags + ; + ; this routine was with tiny differences in the + ; sinclair zx81 rom for the mantissa multiply + +__LMUL: + and a ; reset carry flag + sbc hl,hl ; result bits 32..47 = 0 + exx + sbc hl,hl ; result bits 48..63 = 0 + exx + ld a,b ; mpr is b'c'ac + ld b,33 ; initialize loop counter + jp __LMULSTART + +__LMULLOOP: + jr nc,__LMULNOADD ; JP is 2 cycles faster than JR. Since it's inside a LOOP + ; it can save up to 33 * 2 = 66 cycles + ; But JR if 3 cycles faster if JUMP not taken! + add hl,de ; result += mpd + exx + adc hl,de + exx + +__LMULNOADD: + exx + rr h ; right shift upper + rr l ; 32bit of result + exx + rr h + rr l + +__LMULSTART: + exx + rr b ; right shift mpr/ + rr c ; lower 32bit of result + exx + rra ; equivalent to rr a + rr c + djnz __LMULLOOP + + ret ; result in h'l'hlb'c'ac + +#line 2 "mul32.asm" + +__MUL32: ; multiplies 32 bit un/signed integer. + ; First operand stored in DEHL, and 2nd onto stack + ; Lowest part of 2nd operand on top of the stack + ; returns the result in DE.HL + exx + pop hl ; Return ADDRESS + pop de ; Low part + ex (sp), hl ; CALLEE -> HL = High part + ex de, hl + call __MUL32_64START + +__TO32BIT: ; Converts H'L'HLB'C'AC to DEHL (Discards H'L'HL) + exx + push bc + exx + pop de + ld h, a + ld l, c + ret + + +#line 112 "fact.bas" +#line 1 "print.asm" + +; vim:ts=4:sw=4:et: + ; PRINT command routine + ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that + + + +#line 1 "in_screen.asm" + + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 3 "in_screen.asm" + +__IN_SCREEN: + ; Returns NO carry if current coords (D, E) + ; are OUT of the screen limits (MAXX, MAXY) + + PROC + LOCAL __IN_SCREEN_ERR + + ld hl, MAXX + ld a, e + cp (hl) + jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + + ld a, d + inc hl + cp (hl) + ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + ;; ret + ret c ; Return if carry (OK) + +__IN_SCREEN_ERR: +__OUT_OF_SCREEN_ERR: + ; Jumps here if out of screen + ld a, ERROR_OutOfScreen + jp __STOP ; Saves error code and exits + + ENDP +#line 8 "print.asm" +#line 1 "table_jump.asm" + + +JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A + add a, a + +JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE + ld e, a + ld d, 0 + +JUMP_HL_PLUS_DE: ; Does JP (HL + DE) + add hl, de + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl +CALL_HL: + jp (hl) + +#line 9 "print.asm" +#line 1 "ink.asm" + + ; Sets ink color in ATTR_P permanently +; Parameter: Paper color in A register + +#line 1 "const.asm" + + ; Global constants + + P_FLAG EQU 23697 + FLAGS2 EQU 23681 + ATTR_P EQU 23693 ; permanet ATTRIBUTES + ATTR_T EQU 23695 ; temporary ATTRIBUTES + CHARS EQU 23606 ; Pointer to ROM/RAM Charset + UDG EQU 23675 ; Pointer to UDG Charset + MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars + +#line 5 "ink.asm" + +INK: + PROC + LOCAL __SET_INK + LOCAL __SET_INK2 + + ld de, ATTR_P + +__SET_INK: + cp 8 + jr nz, __SET_INK2 + + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + or 7 ; Set bits 0,1,2 to enable transparency + ld (de), a + ret + +__SET_INK2: + ; Another entry. This will set the ink color at location pointer by DE + and 7 ; # Gets color mod 8 + ld b, a ; Saves the color + ld a, (de) + and 0F8h ; Clears previous value + or b + ld (de), a + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + and 0F8h ; Reset bits 0,1,2 sign to disable transparency + ld (de), a ; Store new attr + ret + + ; Sets the INK color passed in A register in the ATTR_T variable +INK_TMP: + ld de, ATTR_T + jp __SET_INK + + ENDP + +#line 10 "print.asm" +#line 1 "paper.asm" + + ; Sets paper color in ATTR_P permanently +; Parameter: Paper color in A register + + + +PAPER: + PROC + LOCAL __SET_PAPER + LOCAL __SET_PAPER2 + + ld de, ATTR_P + +__SET_PAPER: + cp 8 + jr nz, __SET_PAPER2 + inc de + ld a, (de) + or 038h + ld (de), a + ret + + ; Another entry. This will set the paper color at location pointer by DE +__SET_PAPER2: + and 7 ; # Remove + rlca + rlca + rlca ; a *= 8 + + ld b, a ; Saves the color + ld a, (de) + and 0C7h ; Clears previous value + or b + ld (de), a + inc de ; Points to MASK_T or MASK_P accordingly + ld a, (de) + and 0C7h ; Resets bits 3,4,5 + ld (de), a + ret + + + ; Sets the PAPER color passed in A register in the ATTR_T variable +PAPER_TMP: + ld de, ATTR_T + jp __SET_PAPER + ENDP + +#line 11 "print.asm" +#line 1 "flash.asm" + + ; Sets flash flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +FLASH: + ld de, ATTR_P +__SET_FLASH: + ; Another entry. This will set the flash flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + ld b, a ; Saves the color + ld a, (de) + and 07Fh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the FLASH flag passed in A register in the ATTR_T variable +FLASH_TMP: + ld de, ATTR_T + jr __SET_FLASH + +#line 12 "print.asm" +#line 1 "bright.asm" + + ; Sets bright flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +BRIGHT: + ld de, ATTR_P + +__SET_BRIGHT: + ; Another entry. This will set the bright flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + rrca + ld b, a ; Saves the color + ld a, (de) + and 0BFh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable +BRIGHT_TMP: + ld de, ATTR_T + jr __SET_BRIGHT + +#line 13 "print.asm" +#line 1 "over.asm" + + ; Sets OVER flag in P_FLAG permanently +; Parameter: OVER flag in bit 0 of A register +#line 1 "copy_attr.asm" + + + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" + + + +COPY_ATTR: + ; Just copies current permanent attribs to temporal attribs + ; and sets print mode + PROC + + LOCAL INVERSE1 + LOCAL __REFRESH_TMP + + INVERSE1 EQU 02Fh + + ld hl, (ATTR_P) + ld (ATTR_T), hl + + ld hl, FLAGS2 + call __REFRESH_TMP + + ld hl, P_FLAG + call __REFRESH_TMP + + +__SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) + + + LOCAL TABLE + LOCAL CONT2 + + rra ; Over bit to carry + ld a, (FLAGS2) + rla ; Over bit in bit 1, Over2 bit in bit 2 + and 3 ; Only bit 0 and 1 (OVER flag) + + ld c, a + ld b, 0 + + ld hl, TABLE + add hl, bc + ld a, (hl) + ld (PRINT_MODE), a + + ld hl, (P_FLAG) + xor a ; NOP -> INVERSE0 + bit 2, l + jr z, CONT2 + ld a, INVERSE1 ; CPL -> INVERSE1 + +CONT2: + ld (INVERSE_MODE), a + ret + +TABLE: + nop ; NORMAL MODE + xor (hl) ; OVER 1 MODE + and (hl) ; OVER 2 MODE + or (hl) ; OVER 3 MODE + +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" + +__REFRESH_TMP: + ld a, (hl) + and 10101010b + ld c, a + rra + or c + ld (hl), a + ret + + ENDP + +#line 4 "over.asm" + + +OVER: + PROC + + ld c, a ; saves it for later + and 2 + ld hl, FLAGS2 + res 1, (HL) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 ; # Convert to 0/1 + add a, a; # Shift left 1 bit for permanent + + ld hl, P_FLAG + res 1, (hl) + or (hl) + ld (hl), a + ret + + ; Sets OVER flag in P_FLAG temporarily +OVER_TMP: + ld c, a ; saves it for later + and 2 ; gets bit 1; clears carry + rra + ld hl, FLAGS2 + res 0, (hl) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 + ld hl, P_FLAG + res 0, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 14 "print.asm" +#line 1 "inverse.asm" + + ; Sets INVERSE flag in P_FLAG permanently +; Parameter: INVERSE flag in bit 0 of A register + + + +INVERSE: + PROC + + and 1 ; # Convert to 0/1 + add a, a; # Shift left 3 bits for permanent + add a, a + add a, a + ld hl, P_FLAG + res 3, (hl) + or (hl) + ld (hl), a + ret + + ; Sets INVERSE flag in P_FLAG temporarily +INVERSE_TMP: + and 1 + add a, a + add a, a; # Shift left 2 bits for temporary + ld hl, P_FLAG + res 2, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 15 "print.asm" +#line 1 "bold.asm" + + ; Sets BOLD flag in P_FLAG permanently +; Parameter: BOLD flag in bit 0 of A register + + +BOLD: + PROC + + and 1 + rlca + rlca + rlca + ld hl, FLAGS2 + res 3, (HL) + or (hl) + ld (hl), a + ret + + ; Sets BOLD flag in P_FLAG temporarily +BOLD_TMP: + and 1 + rlca + rlca + ld hl, FLAGS2 + res 2, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 16 "print.asm" +#line 1 "italic.asm" + + ; Sets ITALIC flag in P_FLAG permanently +; Parameter: ITALIC flag in bit 0 of A register + + +ITALIC: + PROC + + and 1 + rrca + rrca + rrca + ld hl, FLAGS2 + res 5, (HL) + or (hl) + ld (hl), a + ret + + ; Sets ITALIC flag in P_FLAG temporarily +ITALIC_TMP: + and 1 + rrca + rrca + rrca + rrca + ld hl, FLAGS2 + res 4, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 17 "print.asm" + +#line 1 "attr.asm" + + ; Attribute routines +; vim:ts=4:et:sw: + + + + + + + +__ATTR_ADDR: + ; calc start address in DE (as (32 * d) + e) + ; Contributed by Santiago Romero at http://www.speccy.org + ld h, 0 ; 7 T-States + ld a, d ; 4 T-States + add a, a ; a * 2 ; 4 T-States + add a, a ; a * 4 ; 4 T-States + ld l, a ; HL = A * 4 ; 4 T-States + + add hl, hl ; HL = A * 8 ; 15 T-States + add hl, hl ; HL = A * 16 ; 15 T-States + add hl, hl ; HL = A * 32 ; 15 T-States + + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) + add hl, de + + ld de, (SCREEN_ADDR) ; Adds the screen address + add hl, de + + ; Return current screen address in HL + ret + + + ; Sets the attribute at a given screen coordinate (D, E). + ; The attribute is taken from the ATTR_T memory variable + ; Used by PRINT routines +SET_ATTR: + + ; Checks for valid coords + call __IN_SCREEN + ret nc + +__SET_ATTR: + ; Internal __FASTCALL__ Entry used by printing routines + PROC + + call __ATTR_ADDR + ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T + + ld a, d + and (hl) + ld c, a ; C = current screen color, masked + + ld a, d + cpl ; Negate mask + and e ; Mask current attributes + or c ; Mix them + ld (hl), a ; Store result in screen + + ret + + ENDP + + +#line 19 "print.asm" + + ; Putting a comment starting with @INIT
+ ; will make the compiler to add a CALL to
+ ; It is useful for initialization routines. + + +__PRINT_INIT: ; To be called before program starts (initializes library) + PROC + + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + + ld hl, 1821h + ld (MAXX), hl ; Sets current maxX and maxY + + xor a + ld (FLAGS2), a + + ret + + +__PRINTCHAR: ; Print character store in accumulator (A register) + ; Modifies H'L', B'C', A'F', D'E', A + + LOCAL PO_GR_1 + + LOCAL __PRCHAR + LOCAL __PRINT_CONT + LOCAL __PRINT_CONT2 + LOCAL __PRINT_JUMP + LOCAL __SRCADDR + LOCAL __PRINT_UDG + LOCAL __PRGRAPH + LOCAL __PRINT_START + + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 + +__PRINT_JUMP: + jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively + +__PRINT_START: + cp ' ' + jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones + + exx ; Switch to alternative registers + ex af, af' ; Saves a value (char to print) for later + + call __LOAD_S_POSN + + ; At this point we have the new coord + ld hl, (SCREEN_ADDR) + + ld a, d + ld c, a ; Saves it for later + + and 0F8h ; Masks 3 lower bit ; zy + ld d, a + + ld a, c ; Recovers it + and 07h ; MOD 7 ; y1 + rrca + rrca + rrca + + or e + ld e, a + add hl, de ; HL = Screen address + DE + ex de, hl ; DE = Screen address + + ex af, af' + + cp 80h ; Is it an UDG or a ? + jp c, __SRCADDR + + cp 90h + jp nc, __PRINT_UDG + + ; Print a 8 bit pattern (80h to 8Fh) + + ld b, a + call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 + ld hl, MEM0 + jp __PRGRAPH + + PO_GR_1 EQU 0B38h + +__PRINT_UDG: + sub 90h ; Sub ASC code + ld bc, (UDG) + jp __PRGRAPH0 + + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source +__SRCADDR: + ld bc, (CHARS) + +__PRGRAPH0: + add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org + ld l, a + ld h, 0 ; HL = a * 2 (accumulator) + add hl, hl + add hl, hl ; HL = a * 8 + add hl, bc ; HL = CHARS address + +__PRGRAPH: + ex de, hl ; HL = Write Address, DE = CHARS address + bit 2, (iy + $47) + call nz, __BOLD + bit 4, (iy + $47) + call nz, __ITALIC + ld b, 8 ; 8 bytes per char +__PRCHAR: + ld a, (de) ; DE *must* be ALWAYS source, and HL destiny + +PRINT_MODE: ; Which operation is used to write on the screen + ; Set it with: + ; LD A, + ; LD (PRINT_MODE), A + ; + ; Available opertions: + ; NORMAL: 0h --> NOP ; OVER 0 + ; XOR : AEh --> XOR (HL) ; OVER 1 + ; OR : B6h --> OR (HL) ; PUTSPRITE + ; AND : A6h --> AND (HL) ; PUTMASK + nop ; + +INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 + nop ; 2F -> CPL -> INVERSE 1 + + ld (hl), a + + inc de + inc h ; Next line + djnz __PRCHAR + + call __LOAD_S_POSN + push de + call __SET_ATTR + pop de + inc e ; COL = COL + 1 + ld hl, (MAXX) + ld a, e + dec l ; l = MAXX + cp l ; Lower than max? + jp c, __PRINT_CONT; Nothing to do + call __PRINT_EOL1 + exx ; counteracts __PRINT_EOL1 exx + jp __PRINT_CONT2 + +__PRINT_CONT: + call __SAVE_S_POSN + +__PRINT_CONT2: + exx + ret + + ; ------------- SPECIAL CHARS (< 32) ----------------- + +__PRINT_SPECIAL: ; Jumps here if it is a special char + exx + ld hl, __PRINT_TABLE + jp JUMP_HL_PLUS_2A + + +PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence + exx + +__PRINT_0Dh: ; Called WHEN printing CHR$(13) + call __LOAD_S_POSN + +__PRINT_EOL1: ; Another entry called from PRINT when next line required + ld e, 0 + +__PRINT_EOL2: + ld a, d + inc a + +__PRINT_AT1_END: + ld hl, (MAXY) + cp l + jr c, __PRINT_EOL_END ; Carry if (MAXY) < d + xor a + +__PRINT_EOL_END: + ld d, a + +__PRINT_AT2_END: + call __SAVE_S_POSN + exx + ret + +__PRINT_COM: + exx + push hl + push de + push bc + call PRINT_COMMA + pop bc + pop de + pop hl + ret + +__PRINT_TAB: + ld hl, __PRINT_TAB1 + jp __PRINT_SET_STATE + +__PRINT_TAB1: + ld (MEM0), a + ld hl, __PRINT_TAB2 + ld (PRINT_JUMP_STATE), hl + ret + +__PRINT_TAB2: + ld a, (MEM0) ; Load tab code (ignore the current one) + push hl + push de + push bc + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + call PRINT_TAB + pop bc + pop de + pop hl + ret + +__PRINT_NOP: +__PRINT_RESTART: + ld hl, __PRINT_START + jp __PRINT_SET_STATE + +__PRINT_AT: + ld hl, __PRINT_AT1 + +__PRINT_SET_STATE: + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + exx + ret + +__PRINT_AT1: ; Jumps here if waiting for 1st parameter + exx + ld hl, __PRINT_AT2 + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + jp __PRINT_AT1_END + +__PRINT_AT2: + exx + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + ld e, a + ld hl, (MAXX) + cp (hl) + jr c, __PRINT_AT2_END + jr __PRINT_EOL1 + +__PRINT_DEL: + call __LOAD_S_POSN ; Gets current screen position + dec e + ld a, -1 + cp e + jp nz, __PRINT_AT2_END + ld hl, (MAXX) + ld e, l + dec e + dec e + dec d + cp d + jp nz, __PRINT_AT2_END + ld d, h + dec d + jp __PRINT_AT2_END + +__PRINT_INK: + ld hl, __PRINT_INK2 + jp __PRINT_SET_STATE + +__PRINT_INK2: + exx + call INK_TMP + jp __PRINT_RESTART + +__PRINT_PAP: + ld hl, __PRINT_PAP2 + jp __PRINT_SET_STATE + +__PRINT_PAP2: + exx + call PAPER_TMP + jp __PRINT_RESTART + +__PRINT_FLA: + ld hl, __PRINT_FLA2 + jp __PRINT_SET_STATE + +__PRINT_FLA2: + exx + call FLASH_TMP + jp __PRINT_RESTART + +__PRINT_BRI: + ld hl, __PRINT_BRI2 + jp __PRINT_SET_STATE + +__PRINT_BRI2: + exx + call BRIGHT_TMP + jp __PRINT_RESTART + +__PRINT_INV: + ld hl, __PRINT_INV2 + jp __PRINT_SET_STATE + +__PRINT_INV2: + exx + call INVERSE_TMP + jp __PRINT_RESTART + +__PRINT_OVR: + ld hl, __PRINT_OVR2 + jp __PRINT_SET_STATE + +__PRINT_OVR2: + exx + call OVER_TMP + jp __PRINT_RESTART + +__PRINT_BOLD: + ld hl, __PRINT_BOLD2 + jp __PRINT_SET_STATE + +__PRINT_BOLD2: + exx + call BOLD_TMP + jp __PRINT_RESTART + +__PRINT_ITA: + ld hl, __PRINT_ITA2 + jp __PRINT_SET_STATE + +__PRINT_ITA2: + exx + call ITALIC_TMP + jp __PRINT_RESTART + + +__BOLD: + push hl + ld hl, MEM0 + ld b, 8 +__BOLD_LOOP: + ld a, (de) + ld c, a + rlca + or c + ld (hl), a + inc hl + inc de + djnz __BOLD_LOOP + pop hl + ld de, MEM0 + ret + + +__ITALIC: + push hl + ld hl, MEM0 + ex de, hl + ld bc, 8 + ldir + ld hl, MEM0 + srl (hl) + inc hl + srl (hl) + inc hl + srl (hl) + inc hl + inc hl + inc hl + sla (hl) + inc hl + sla (hl) + inc hl + sla (hl) + pop hl + ld de, MEM0 + ret + +PRINT_COMMA: + call __LOAD_S_POSN + ld a, e + and 16 + add a, 16 + +PRINT_TAB: + PROC + LOCAL LOOP, CONTINUE + + inc a + call __LOAD_S_POSN ; e = current row + ld d, a + ld a, e + cp 21h + jr nz, CONTINUE + ld e, -1 +CONTINUE: + ld a, d + inc e + sub e ; A = A - E + and 31 ; + ret z ; Already at position E + ld b, a +LOOP: + ld a, ' ' + call __PRINTCHAR + djnz LOOP + ret + ENDP + +PRINT_AT: ; CHanges cursor to ROW, COL + ; COL in A register + ; ROW in stack + + pop hl ; Ret address + ex (sp), hl ; callee H = ROW + ld l, a + ex de, hl + + call __IN_SCREEN + ret nc ; Return if out of screen + + jp __SAVE_S_POSN + + LOCAL __PRINT_COM + LOCAL __BOLD + LOCAL __BOLD_LOOP + LOCAL __ITALIC + LOCAL __PRINT_EOL1 + LOCAL __PRINT_EOL2 + LOCAL __PRINT_AT1 + LOCAL __PRINT_AT2 + LOCAL __PRINT_AT2_END + LOCAL __PRINT_BOLD + LOCAL __PRINT_BOLD2 + LOCAL __PRINT_ITA + LOCAL __PRINT_ITA2 + LOCAL __PRINT_INK + LOCAL __PRINT_PAP + LOCAL __PRINT_SET_STATE + LOCAL __PRINT_TABLE + LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 + +__PRINT_TABLE: ; Jump table for 0 .. 22 codes + + DW __PRINT_NOP ; 0 + DW __PRINT_NOP ; 1 + DW __PRINT_NOP ; 2 + DW __PRINT_NOP ; 3 + DW __PRINT_NOP ; 4 + DW __PRINT_NOP ; 5 + DW __PRINT_COM ; 6 COMMA + DW __PRINT_NOP ; 7 + DW __PRINT_DEL ; 8 DEL + DW __PRINT_NOP ; 9 + DW __PRINT_NOP ; 10 + DW __PRINT_NOP ; 11 + DW __PRINT_NOP ; 12 + DW __PRINT_0Dh ; 13 + DW __PRINT_BOLD ; 14 + DW __PRINT_ITA ; 15 + DW __PRINT_INK ; 16 + DW __PRINT_PAP ; 17 + DW __PRINT_FLA ; 18 + DW __PRINT_BRI ; 19 + DW __PRINT_INV ; 20 + DW __PRINT_OVR ; 21 + DW __PRINT_AT ; 22 AT + DW __PRINT_TAB ; 23 TAB + + ENDP + + +#line 113 "fact.bas" +#line 1 "printstr.asm" + + + + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 5 "printstr.asm" + + ; PRINT command routine + ; Prints string pointed by HL + +PRINT_STR: +__PRINTSTR: ; __FASTCALL__ Entry to print_string + PROC + LOCAL __PRINT_STR_LOOP + LOCAL __PRINT_STR_END + + ld d, a ; Saves A reg (Flag) for later + + ld a, h + or l + ret z ; Return if the pointer is NULL + + push hl + + ld c, (hl) + inc hl + ld b, (hl) + inc hl ; BC = LEN(a$); HL = &a$ + +__PRINT_STR_LOOP: + ld a, b + or c + jr z, __PRINT_STR_END ; END if BC (counter = 0) + + ld a, (hl) + call __PRINTCHAR + inc hl + dec bc + jp __PRINT_STR_LOOP + +__PRINT_STR_END: + pop hl + ld a, d ; Recovers A flag + or a ; If not 0 this is a temporary string. Free it + ret z + jp __MEM_FREE ; Frees str from heap and return from there + +__PRINT_STR: + ; Fastcall Entry + ; It ONLY prints strings + ; HL = String start + ; BC = String length (Number of chars) + push hl ; Push str address for later + ld d, a ; Saves a FLAG + jp __PRINT_STR_LOOP + + ENDP + +#line 114 "fact.bas" +#line 1 "printu32.asm" + +#line 1 "printi32.asm" + +#line 1 "printnum.asm" + + + + +__PRINTU_START: + PROC + + LOCAL __PRINTU_CONT + + ld a, b + or a + jp nz, __PRINTU_CONT + + ld a, '0' + jp __PRINT_DIGIT + + +__PRINTU_CONT: + pop af + push bc + call __PRINT_DIGIT + pop bc + djnz __PRINTU_CONT + ret + + ENDP + + +__PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers + ld a, '-' + jp __PRINT_DIGIT + + __PRINT_DIGIT EQU __PRINTCHAR ; PRINTS the char in A register, and puts its attrs + + +#line 2 "printi32.asm" +#line 1 "neg32.asm" + +__ABS32: + bit 7, d + ret z + +__NEG32: ; Negates DEHL (Two's complement) + ld a, l + cpl + ld l, a + + ld a, h + cpl + ld h, a + + ld a, e + cpl + ld e, a + + ld a, d + cpl + ld d, a + + inc l + ret nz + + inc h + ret nz + + inc de + ret + +#line 3 "printi32.asm" +#line 1 "div32.asm" + + + + ; --------------------------------------------------------- +__DIVU32: ; 32 bit unsigned division + ; DEHL = Dividend, Stack Top = Divisor + ; OPERANDS P = Dividend, Q = Divisor => OPERATION => P / Q + ; + ; Changes A, BC DE HL B'C' D'E' H'L' + ; --------------------------------------------------------- + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + +__DIVU32START: ; Performs D'E'H'L' / HLDE + ; Now switch to DIVIDEND = B'C'BC / DIVISOR = D'E'DE (A / B) + push de ; push Lowpart(Q) + ex de, hl ; DE = HL + ld hl, 0 + exx + ld b, h + ld c, l + pop hl + push de + ex de, hl + ld hl, 0 ; H'L'HL = 0 + exx + pop bc ; Pop HightPart(B) => B = B'C'BC + exx + + ld a, 32 ; Loop count + +__DIV32LOOP: + sll c ; B'C'BC << 1 ; Output most left bit to carry + rl b + exx + rl c + rl b + exx + + adc hl, hl + exx + adc hl, hl + exx + + sbc hl,de + exx + sbc hl,de + exx + jp nc, __DIV32NOADD ; use JP inside a loop for being faster + + add hl, de + exx + adc hl, de + exx + dec bc + +__DIV32NOADD: + dec a + jp nz, __DIV32LOOP ; use JP inside a loop for being faster + ; At this point, quotient is stored in B'C'BC and the reminder in H'L'HL + + push hl + exx + pop de + ex de, hl ; D'E'H'L' = 32 bits modulus + push bc + exx + pop de ; DE = B'C' + ld h, b + ld l, c ; DEHL = quotient D'E'H'L' = Modulus + + ret ; DEHL = quotient, D'E'H'L' = Modulus + + + +__MODU32: ; 32 bit modulus for 32bit unsigned division + ; DEHL = Dividend, Stack Top = Divisor (DE, HL) + + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + + call __DIVU32START ; At return, modulus is at D'E'H'L' + +__MODU32START: + + exx + push de + push hl + + exx + pop hl + pop de + + ret + + +__DIVI32: ; 32 bit signed division + ; DEHL = Dividend, Stack Top = Divisor + ; A = Dividend, B = Divisor => A / B + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + +__DIVI32START: + exx + ld a, d ; Save sign + ex af, af' + bit 7, d ; Negative? + call nz, __NEG32 ; Negates DEHL + + exx ; Now works with H'L'D'E' + ex af, af' + xor h + ex af, af' ; Stores sign of the result for later + + bit 7, h ; Negative? + ex de, hl ; HLDE = DEHL + call nz, __NEG32 + ex de, hl + + call __DIVU32START + ex af, af' ; Recovers sign + and 128 ; positive? + ret z + + jp __NEG32 ; Negates DEHL and returns from there + + +__MODI32: ; 32bits signed division modulus + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + + call __DIVI32START + jp __MODU32START + +#line 4 "printi32.asm" + + + +__PRINTI32: + ld a, d + or a + jp p, __PRINTU32 + + call __PRINT_MINUS + call __NEG32 + +__PRINTU32: + PROC + LOCAL __PRINTU_LOOP + + ld b, 0 ; Counter + +__PRINTU_LOOP: + ld a, h + or l + or d + or e + jp z, __PRINTU_START + + push bc + + ld bc, 0 + push bc + ld bc, 10 + push bc ; Push 00 0A (10 Dec) into the stack = divisor + + call __DIVU32 ; Divides by 32. D'E'H'L' contains modulo (L' since < 10) + pop bc + + exx + ld a, l + or '0' ; Stores ASCII digit (must be print in reversed order) + push af + exx + inc b + jp __PRINTU_LOOP ; Uses JP in loops + + ENDP + +#line 2 "printu32.asm" + +#line 115 "fact.bas" +#line 1 "printu8.asm" + +#line 1 "printi8.asm" + + +#line 1 "div8.asm" + + ; -------------------------------- +__DIVU8: ; 8 bit unsigned integer division + ; Divides (Top of stack, High Byte) / A + pop hl ; -------------------------------- + ex (sp), hl ; CALLEE + +__DIVU8_FAST: ; Does A / H + ld l, h + ld h, a ; At this point do H / L + + ld b, 8 + xor a ; A = 0, Carry Flag = 0 + +__DIV8LOOP: + sla h + rla + cp l + jr c, __DIV8NOSUB + sub l + inc h + +__DIV8NOSUB: + djnz __DIV8LOOP + + ld l, a ; save remainder + ld a, h ; + + ret ; a = Quotient, + + + ; -------------------------------- +__DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A + pop hl ; -------------------------------- + ex (sp), hl + +__DIVI8_FAST: + ld e, a ; store operands for later + ld c, h + + or a ; negative? + jp p, __DIV8A + neg ; Make it positive + +__DIV8A: + ex af, af' + ld a, h + or a + jp p, __DIV8B + neg + ld h, a ; make it positive + +__DIV8B: + ex af, af' + + call __DIVU8_FAST + + ld a, c + xor l ; bit 7 of A = 1 if result is negative + + ld a, h ; Quotient + ret p ; return if positive + + neg + ret + + +__MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) + pop hl + ex (sp), hl ; CALLEE + +__MODU8_FAST: ; __FASTCALL__ entry + call __DIVU8_FAST + ld a, l ; Remainder + + ret ; a = Modulus + + +__MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) + pop hl + ex (sp), hl ; CALLEE + +__MODI8_FAST: ; __FASTCALL__ entry + call __DIVI8_FAST + ld a, l ; remainder + + ret ; a = Modulus + +#line 3 "printi8.asm" + +__PRINTI8: ; Prints an 8 bits number in Accumulator (A) + ; Converts 8 to 32 bits + or a + jp p, __PRINTU8 + + push af + call __PRINT_MINUS + pop af + neg + +__PRINTU8: + PROC + + LOCAL __PRINTU_LOOP + + ld b, 0 ; Counter + +__PRINTU_LOOP: + or a + jp z, __PRINTU_START + + push bc + ld h, 10 + call __DIVU8_FAST ; Divides by 10. D'E'H'L' contains modulo (L' since < 10) + pop bc + + ld a, l + or '0' ; Stores ASCII digit (must be print in reversed order) + push af + ld a, h + inc b + jp __PRINTU_LOOP ; Uses JP in loops + + ENDP + +#line 2 "printu8.asm" + +#line 116 "fact.bas" +#line 1 "sub32.asm" + + ; SUB32 + ; Perform TOP of the stack - DEHL + ; Pops operand out of the stack (CALLEE) + ; and returns result in DEHL. Carry an Z are set correctly + +__SUB32: + exx + pop bc ; saves return address in BC' + exx + + or a ; clears carry flag + ld b, h ; Operands come reversed => BC <- HL, HL = HL - BC + ld c, l + pop hl + sbc hl, bc + ex de, hl + + ld b, h ; High part (DE) now in HL. Repeat operation + ld c, l + pop hl + sbc hl, bc + ex de, hl ; DEHL now has de 32 bit result + + exx + push bc ; puts return address back + exx + ret +#line 117 "fact.bas" + +ZXBASIC_USER_DATA: +_x: + DEFB 00 +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/fact.bas b/tests/functional/fact.bas new file mode 100644 index 000000000..3e1a0a5cd --- /dev/null +++ b/tests/functional/fact.bas @@ -0,0 +1,15 @@ +REM Factorial recursive test + +function fact(x as ulong) as ulong + if x < 2 then + return 1 + end if + + return x * fact(x - 1) +end function + +cls +for x = 1 To 10: + print "Fact ("; x; ") = "; fact(x) +next x + diff --git a/tests/functional/subrec.asm b/tests/functional/subrec.asm new file mode 100644 index 000000000..1927e0963 --- /dev/null +++ b/tests/functional/subrec.asm @@ -0,0 +1,2174 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + call __PRINT_INIT + call CLS + ld a, 1 + ld (_x), a + jp __LABEL0 +__LABEL3: + ld de, 0 + ld hl, 1 + ld (_result), hl + ld (_result + 2), de + ld a, (_x) + ld l, a + ld h, 0 + ld e, h + ld d, h + push de + push hl + call _fact + ld hl, __LABEL5 + xor a + call __PRINTSTR + ld a, (_x) + call __PRINTU8 + ld hl, __LABEL6 + xor a + call __PRINTSTR + ld hl, (_result) + ld de, (_result + 2) + call __PRINTU32 + call PRINT_EOL +__LABEL4: + ld a, (_x) + inc a + ld (_x), a +__LABEL0: + ld a, 10 + ld hl, (_x - 1) + cp h + jp nc, __LABEL3 +__LABEL2: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +_fact: + push ix + ld ix, 0 + add ix, sp + ld l, (ix+4) + ld h, (ix+5) + ld e, (ix+6) + ld d, (ix+7) + push de + push hl + ld de, 0 + ld hl, 2 + call __SUB32 + jp c, _fact__leave +__LABEL8: + ld l, (ix+4) + ld h, (ix+5) + ld e, (ix+6) + ld d, (ix+7) + push de + push hl + ld hl, (_result + 2) + push hl + ld hl, (_result) + push hl + pop hl + pop de + call __MUL32 + ld (_result), hl + ld (_result + 2), de + ld l, (ix+4) + ld h, (ix+5) + ld e, (ix+6) + ld d, (ix+7) + push de + push hl + ld de, 0 + ld hl, 1 + call __SUB32 + push de + push hl + call _fact +_fact__leave: + ld sp, ix + pop ix + exx + pop hl + pop bc + ex (sp), hl + exx + ret +__LABEL5: + DEFW 0006h + DEFB 46h + DEFB 61h + DEFB 63h + DEFB 74h + DEFB 20h + DEFB 28h +__LABEL6: + DEFW 0004h + DEFB 29h + DEFB 20h + DEFB 3Dh + DEFB 20h +#line 1 "cls.asm" + + ; JUMPS directly to spectrum CLS + ; This routine does not clear lower screen + + ;CLS EQU 0DAFh + + ; Our faster implementation + +#line 1 "sposn.asm" + + ; Printing positioning library. + PROC + LOCAL ECHO_E + +__LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. + ld de, (S_POSN) + ld hl, (MAXX) + or a + sbc hl, de + ex de, hl + ret + + +__SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. + ld hl, (MAXX) + or a + sbc hl, de + ld (S_POSN), hl ; saves it again + ret + + + ECHO_E EQU 23682 + MAXX EQU ECHO_E ; Max X position + 1 + MAXY EQU MAXX + 1 ; Max Y position + 1 + + S_POSN EQU 23688 + POSX EQU S_POSN ; Current POS X + POSY EQU S_POSN + 1 ; Current POS Y + + ENDP + +#line 9 "cls.asm" + +CLS: + PROC + + LOCAL COORDS + LOCAL __CLS_SCR + LOCAL ATTR_P + LOCAL SCREEN + + ld hl, 0 + ld (COORDS), hl + ld hl, 1821h + ld (S_POSN), hl +__CLS_SCR: + ld hl, SCREEN + ld (hl), 0 + ld d, h + ld e, l + inc de + ld bc, 6144 + ldir + + ; Now clear attributes + + ld a, (ATTR_P) + ld (hl), a + ld bc, 767 + ldir + ret + + COORDS EQU 23677 + SCREEN EQU 16384 ; Default start of the screen (can be changed) + ATTR_P EQU 23693 + ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address + + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines + ; to get the start of the screen + ENDP + +#line 122 "subrec.bas" +#line 1 "mul32.asm" + +#line 1 "_mul32.asm" + + +; Ripped from: http://www.andreadrian.de/oldcpu/z80_number_cruncher.html#moztocid784223 + ; Used with permission. + ; Multiplies 32x32 bit integer (DEHL x D'E'H'L') + ; 64bit result is returned in H'L'H L B'C'A C + + +__MUL32_64START: + push hl + exx + ld b, h + ld c, l ; BC = Low Part (A) + pop hl ; HL = Load Part (B) + ex de, hl ; DE = Low Part (B), HL = HightPart(A) (must be in B'C') + push hl + + exx + pop bc ; B'C' = HightPart(A) + exx ; A = B'C'BC , B = D'E'DE + + ; multiply routine 32 * 32bit = 64bit + ; h'l'hlb'c'ac = b'c'bc * d'e'de + ; needs register a, changes flags + ; + ; this routine was with tiny differences in the + ; sinclair zx81 rom for the mantissa multiply + +__LMUL: + and a ; reset carry flag + sbc hl,hl ; result bits 32..47 = 0 + exx + sbc hl,hl ; result bits 48..63 = 0 + exx + ld a,b ; mpr is b'c'ac + ld b,33 ; initialize loop counter + jp __LMULSTART + +__LMULLOOP: + jr nc,__LMULNOADD ; JP is 2 cycles faster than JR. Since it's inside a LOOP + ; it can save up to 33 * 2 = 66 cycles + ; But JR if 3 cycles faster if JUMP not taken! + add hl,de ; result += mpd + exx + adc hl,de + exx + +__LMULNOADD: + exx + rr h ; right shift upper + rr l ; 32bit of result + exx + rr h + rr l + +__LMULSTART: + exx + rr b ; right shift mpr/ + rr c ; lower 32bit of result + exx + rra ; equivalent to rr a + rr c + djnz __LMULLOOP + + ret ; result in h'l'hlb'c'ac + +#line 2 "mul32.asm" + +__MUL32: ; multiplies 32 bit un/signed integer. + ; First operand stored in DEHL, and 2nd onto stack + ; Lowest part of 2nd operand on top of the stack + ; returns the result in DE.HL + exx + pop hl ; Return ADDRESS + pop de ; Low part + ex (sp), hl ; CALLEE -> HL = High part + ex de, hl + call __MUL32_64START + +__TO32BIT: ; Converts H'L'HLB'C'AC to DEHL (Discards H'L'HL) + exx + push bc + exx + pop de + ld h, a + ld l, c + ret + + +#line 123 "subrec.bas" +#line 1 "print.asm" + +; vim:ts=4:sw=4:et: + ; PRINT command routine + ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that + + + +#line 1 "in_screen.asm" + + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 3 "in_screen.asm" + +__IN_SCREEN: + ; Returns NO carry if current coords (D, E) + ; are OUT of the screen limits (MAXX, MAXY) + + PROC + LOCAL __IN_SCREEN_ERR + + ld hl, MAXX + ld a, e + cp (hl) + jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + + ld a, d + inc hl + cp (hl) + ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + ;; ret + ret c ; Return if carry (OK) + +__IN_SCREEN_ERR: +__OUT_OF_SCREEN_ERR: + ; Jumps here if out of screen + ld a, ERROR_OutOfScreen + jp __STOP ; Saves error code and exits + + ENDP +#line 8 "print.asm" +#line 1 "table_jump.asm" + + +JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A + add a, a + +JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE + ld e, a + ld d, 0 + +JUMP_HL_PLUS_DE: ; Does JP (HL + DE) + add hl, de + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl +CALL_HL: + jp (hl) + +#line 9 "print.asm" +#line 1 "ink.asm" + + ; Sets ink color in ATTR_P permanently +; Parameter: Paper color in A register + +#line 1 "const.asm" + + ; Global constants + + P_FLAG EQU 23697 + FLAGS2 EQU 23681 + ATTR_P EQU 23693 ; permanet ATTRIBUTES + ATTR_T EQU 23695 ; temporary ATTRIBUTES + CHARS EQU 23606 ; Pointer to ROM/RAM Charset + UDG EQU 23675 ; Pointer to UDG Charset + MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars + +#line 5 "ink.asm" + +INK: + PROC + LOCAL __SET_INK + LOCAL __SET_INK2 + + ld de, ATTR_P + +__SET_INK: + cp 8 + jr nz, __SET_INK2 + + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + or 7 ; Set bits 0,1,2 to enable transparency + ld (de), a + ret + +__SET_INK2: + ; Another entry. This will set the ink color at location pointer by DE + and 7 ; # Gets color mod 8 + ld b, a ; Saves the color + ld a, (de) + and 0F8h ; Clears previous value + or b + ld (de), a + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + and 0F8h ; Reset bits 0,1,2 sign to disable transparency + ld (de), a ; Store new attr + ret + + ; Sets the INK color passed in A register in the ATTR_T variable +INK_TMP: + ld de, ATTR_T + jp __SET_INK + + ENDP + +#line 10 "print.asm" +#line 1 "paper.asm" + + ; Sets paper color in ATTR_P permanently +; Parameter: Paper color in A register + + + +PAPER: + PROC + LOCAL __SET_PAPER + LOCAL __SET_PAPER2 + + ld de, ATTR_P + +__SET_PAPER: + cp 8 + jr nz, __SET_PAPER2 + inc de + ld a, (de) + or 038h + ld (de), a + ret + + ; Another entry. This will set the paper color at location pointer by DE +__SET_PAPER2: + and 7 ; # Remove + rlca + rlca + rlca ; a *= 8 + + ld b, a ; Saves the color + ld a, (de) + and 0C7h ; Clears previous value + or b + ld (de), a + inc de ; Points to MASK_T or MASK_P accordingly + ld a, (de) + and 0C7h ; Resets bits 3,4,5 + ld (de), a + ret + + + ; Sets the PAPER color passed in A register in the ATTR_T variable +PAPER_TMP: + ld de, ATTR_T + jp __SET_PAPER + ENDP + +#line 11 "print.asm" +#line 1 "flash.asm" + + ; Sets flash flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +FLASH: + ld de, ATTR_P +__SET_FLASH: + ; Another entry. This will set the flash flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + ld b, a ; Saves the color + ld a, (de) + and 07Fh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the FLASH flag passed in A register in the ATTR_T variable +FLASH_TMP: + ld de, ATTR_T + jr __SET_FLASH + +#line 12 "print.asm" +#line 1 "bright.asm" + + ; Sets bright flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +BRIGHT: + ld de, ATTR_P + +__SET_BRIGHT: + ; Another entry. This will set the bright flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + rrca + ld b, a ; Saves the color + ld a, (de) + and 0BFh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable +BRIGHT_TMP: + ld de, ATTR_T + jr __SET_BRIGHT + +#line 13 "print.asm" +#line 1 "over.asm" + + ; Sets OVER flag in P_FLAG permanently +; Parameter: OVER flag in bit 0 of A register +#line 1 "copy_attr.asm" + + + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" + + + +COPY_ATTR: + ; Just copies current permanent attribs to temporal attribs + ; and sets print mode + PROC + + LOCAL INVERSE1 + LOCAL __REFRESH_TMP + + INVERSE1 EQU 02Fh + + ld hl, (ATTR_P) + ld (ATTR_T), hl + + ld hl, FLAGS2 + call __REFRESH_TMP + + ld hl, P_FLAG + call __REFRESH_TMP + + +__SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) + + + LOCAL TABLE + LOCAL CONT2 + + rra ; Over bit to carry + ld a, (FLAGS2) + rla ; Over bit in bit 1, Over2 bit in bit 2 + and 3 ; Only bit 0 and 1 (OVER flag) + + ld c, a + ld b, 0 + + ld hl, TABLE + add hl, bc + ld a, (hl) + ld (PRINT_MODE), a + + ld hl, (P_FLAG) + xor a ; NOP -> INVERSE0 + bit 2, l + jr z, CONT2 + ld a, INVERSE1 ; CPL -> INVERSE1 + +CONT2: + ld (INVERSE_MODE), a + ret + +TABLE: + nop ; NORMAL MODE + xor (hl) ; OVER 1 MODE + and (hl) ; OVER 2 MODE + or (hl) ; OVER 3 MODE + +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" + +__REFRESH_TMP: + ld a, (hl) + and 10101010b + ld c, a + rra + or c + ld (hl), a + ret + + ENDP + +#line 4 "over.asm" + + +OVER: + PROC + + ld c, a ; saves it for later + and 2 + ld hl, FLAGS2 + res 1, (HL) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 ; # Convert to 0/1 + add a, a; # Shift left 1 bit for permanent + + ld hl, P_FLAG + res 1, (hl) + or (hl) + ld (hl), a + ret + + ; Sets OVER flag in P_FLAG temporarily +OVER_TMP: + ld c, a ; saves it for later + and 2 ; gets bit 1; clears carry + rra + ld hl, FLAGS2 + res 0, (hl) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 + ld hl, P_FLAG + res 0, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 14 "print.asm" +#line 1 "inverse.asm" + + ; Sets INVERSE flag in P_FLAG permanently +; Parameter: INVERSE flag in bit 0 of A register + + + +INVERSE: + PROC + + and 1 ; # Convert to 0/1 + add a, a; # Shift left 3 bits for permanent + add a, a + add a, a + ld hl, P_FLAG + res 3, (hl) + or (hl) + ld (hl), a + ret + + ; Sets INVERSE flag in P_FLAG temporarily +INVERSE_TMP: + and 1 + add a, a + add a, a; # Shift left 2 bits for temporary + ld hl, P_FLAG + res 2, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 15 "print.asm" +#line 1 "bold.asm" + + ; Sets BOLD flag in P_FLAG permanently +; Parameter: BOLD flag in bit 0 of A register + + +BOLD: + PROC + + and 1 + rlca + rlca + rlca + ld hl, FLAGS2 + res 3, (HL) + or (hl) + ld (hl), a + ret + + ; Sets BOLD flag in P_FLAG temporarily +BOLD_TMP: + and 1 + rlca + rlca + ld hl, FLAGS2 + res 2, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 16 "print.asm" +#line 1 "italic.asm" + + ; Sets ITALIC flag in P_FLAG permanently +; Parameter: ITALIC flag in bit 0 of A register + + +ITALIC: + PROC + + and 1 + rrca + rrca + rrca + ld hl, FLAGS2 + res 5, (HL) + or (hl) + ld (hl), a + ret + + ; Sets ITALIC flag in P_FLAG temporarily +ITALIC_TMP: + and 1 + rrca + rrca + rrca + rrca + ld hl, FLAGS2 + res 4, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 17 "print.asm" + +#line 1 "attr.asm" + + ; Attribute routines +; vim:ts=4:et:sw: + + + + + + + +__ATTR_ADDR: + ; calc start address in DE (as (32 * d) + e) + ; Contributed by Santiago Romero at http://www.speccy.org + ld h, 0 ; 7 T-States + ld a, d ; 4 T-States + add a, a ; a * 2 ; 4 T-States + add a, a ; a * 4 ; 4 T-States + ld l, a ; HL = A * 4 ; 4 T-States + + add hl, hl ; HL = A * 8 ; 15 T-States + add hl, hl ; HL = A * 16 ; 15 T-States + add hl, hl ; HL = A * 32 ; 15 T-States + + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) + add hl, de + + ld de, (SCREEN_ADDR) ; Adds the screen address + add hl, de + + ; Return current screen address in HL + ret + + + ; Sets the attribute at a given screen coordinate (D, E). + ; The attribute is taken from the ATTR_T memory variable + ; Used by PRINT routines +SET_ATTR: + + ; Checks for valid coords + call __IN_SCREEN + ret nc + +__SET_ATTR: + ; Internal __FASTCALL__ Entry used by printing routines + PROC + + call __ATTR_ADDR + ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T + + ld a, d + and (hl) + ld c, a ; C = current screen color, masked + + ld a, d + cpl ; Negate mask + and e ; Mask current attributes + or c ; Mix them + ld (hl), a ; Store result in screen + + ret + + ENDP + + +#line 19 "print.asm" + + ; Putting a comment starting with @INIT
+ ; will make the compiler to add a CALL to
+ ; It is useful for initialization routines. + + +__PRINT_INIT: ; To be called before program starts (initializes library) + PROC + + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + + ld hl, 1821h + ld (MAXX), hl ; Sets current maxX and maxY + + xor a + ld (FLAGS2), a + + ret + + +__PRINTCHAR: ; Print character store in accumulator (A register) + ; Modifies H'L', B'C', A'F', D'E', A + + LOCAL PO_GR_1 + + LOCAL __PRCHAR + LOCAL __PRINT_CONT + LOCAL __PRINT_CONT2 + LOCAL __PRINT_JUMP + LOCAL __SRCADDR + LOCAL __PRINT_UDG + LOCAL __PRGRAPH + LOCAL __PRINT_START + + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 + +__PRINT_JUMP: + jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively + +__PRINT_START: + cp ' ' + jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones + + exx ; Switch to alternative registers + ex af, af' ; Saves a value (char to print) for later + + call __LOAD_S_POSN + + ; At this point we have the new coord + ld hl, (SCREEN_ADDR) + + ld a, d + ld c, a ; Saves it for later + + and 0F8h ; Masks 3 lower bit ; zy + ld d, a + + ld a, c ; Recovers it + and 07h ; MOD 7 ; y1 + rrca + rrca + rrca + + or e + ld e, a + add hl, de ; HL = Screen address + DE + ex de, hl ; DE = Screen address + + ex af, af' + + cp 80h ; Is it an UDG or a ? + jp c, __SRCADDR + + cp 90h + jp nc, __PRINT_UDG + + ; Print a 8 bit pattern (80h to 8Fh) + + ld b, a + call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 + ld hl, MEM0 + jp __PRGRAPH + + PO_GR_1 EQU 0B38h + +__PRINT_UDG: + sub 90h ; Sub ASC code + ld bc, (UDG) + jp __PRGRAPH0 + + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source +__SRCADDR: + ld bc, (CHARS) + +__PRGRAPH0: + add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org + ld l, a + ld h, 0 ; HL = a * 2 (accumulator) + add hl, hl + add hl, hl ; HL = a * 8 + add hl, bc ; HL = CHARS address + +__PRGRAPH: + ex de, hl ; HL = Write Address, DE = CHARS address + bit 2, (iy + $47) + call nz, __BOLD + bit 4, (iy + $47) + call nz, __ITALIC + ld b, 8 ; 8 bytes per char +__PRCHAR: + ld a, (de) ; DE *must* be ALWAYS source, and HL destiny + +PRINT_MODE: ; Which operation is used to write on the screen + ; Set it with: + ; LD A, + ; LD (PRINT_MODE), A + ; + ; Available opertions: + ; NORMAL: 0h --> NOP ; OVER 0 + ; XOR : AEh --> XOR (HL) ; OVER 1 + ; OR : B6h --> OR (HL) ; PUTSPRITE + ; AND : A6h --> AND (HL) ; PUTMASK + nop ; + +INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 + nop ; 2F -> CPL -> INVERSE 1 + + ld (hl), a + + inc de + inc h ; Next line + djnz __PRCHAR + + call __LOAD_S_POSN + push de + call __SET_ATTR + pop de + inc e ; COL = COL + 1 + ld hl, (MAXX) + ld a, e + dec l ; l = MAXX + cp l ; Lower than max? + jp c, __PRINT_CONT; Nothing to do + call __PRINT_EOL1 + exx ; counteracts __PRINT_EOL1 exx + jp __PRINT_CONT2 + +__PRINT_CONT: + call __SAVE_S_POSN + +__PRINT_CONT2: + exx + ret + + ; ------------- SPECIAL CHARS (< 32) ----------------- + +__PRINT_SPECIAL: ; Jumps here if it is a special char + exx + ld hl, __PRINT_TABLE + jp JUMP_HL_PLUS_2A + + +PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence + exx + +__PRINT_0Dh: ; Called WHEN printing CHR$(13) + call __LOAD_S_POSN + +__PRINT_EOL1: ; Another entry called from PRINT when next line required + ld e, 0 + +__PRINT_EOL2: + ld a, d + inc a + +__PRINT_AT1_END: + ld hl, (MAXY) + cp l + jr c, __PRINT_EOL_END ; Carry if (MAXY) < d + xor a + +__PRINT_EOL_END: + ld d, a + +__PRINT_AT2_END: + call __SAVE_S_POSN + exx + ret + +__PRINT_COM: + exx + push hl + push de + push bc + call PRINT_COMMA + pop bc + pop de + pop hl + ret + +__PRINT_TAB: + ld hl, __PRINT_TAB1 + jp __PRINT_SET_STATE + +__PRINT_TAB1: + ld (MEM0), a + ld hl, __PRINT_TAB2 + ld (PRINT_JUMP_STATE), hl + ret + +__PRINT_TAB2: + ld a, (MEM0) ; Load tab code (ignore the current one) + push hl + push de + push bc + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + call PRINT_TAB + pop bc + pop de + pop hl + ret + +__PRINT_NOP: +__PRINT_RESTART: + ld hl, __PRINT_START + jp __PRINT_SET_STATE + +__PRINT_AT: + ld hl, __PRINT_AT1 + +__PRINT_SET_STATE: + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + exx + ret + +__PRINT_AT1: ; Jumps here if waiting for 1st parameter + exx + ld hl, __PRINT_AT2 + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + jp __PRINT_AT1_END + +__PRINT_AT2: + exx + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + ld e, a + ld hl, (MAXX) + cp (hl) + jr c, __PRINT_AT2_END + jr __PRINT_EOL1 + +__PRINT_DEL: + call __LOAD_S_POSN ; Gets current screen position + dec e + ld a, -1 + cp e + jp nz, __PRINT_AT2_END + ld hl, (MAXX) + ld e, l + dec e + dec e + dec d + cp d + jp nz, __PRINT_AT2_END + ld d, h + dec d + jp __PRINT_AT2_END + +__PRINT_INK: + ld hl, __PRINT_INK2 + jp __PRINT_SET_STATE + +__PRINT_INK2: + exx + call INK_TMP + jp __PRINT_RESTART + +__PRINT_PAP: + ld hl, __PRINT_PAP2 + jp __PRINT_SET_STATE + +__PRINT_PAP2: + exx + call PAPER_TMP + jp __PRINT_RESTART + +__PRINT_FLA: + ld hl, __PRINT_FLA2 + jp __PRINT_SET_STATE + +__PRINT_FLA2: + exx + call FLASH_TMP + jp __PRINT_RESTART + +__PRINT_BRI: + ld hl, __PRINT_BRI2 + jp __PRINT_SET_STATE + +__PRINT_BRI2: + exx + call BRIGHT_TMP + jp __PRINT_RESTART + +__PRINT_INV: + ld hl, __PRINT_INV2 + jp __PRINT_SET_STATE + +__PRINT_INV2: + exx + call INVERSE_TMP + jp __PRINT_RESTART + +__PRINT_OVR: + ld hl, __PRINT_OVR2 + jp __PRINT_SET_STATE + +__PRINT_OVR2: + exx + call OVER_TMP + jp __PRINT_RESTART + +__PRINT_BOLD: + ld hl, __PRINT_BOLD2 + jp __PRINT_SET_STATE + +__PRINT_BOLD2: + exx + call BOLD_TMP + jp __PRINT_RESTART + +__PRINT_ITA: + ld hl, __PRINT_ITA2 + jp __PRINT_SET_STATE + +__PRINT_ITA2: + exx + call ITALIC_TMP + jp __PRINT_RESTART + + +__BOLD: + push hl + ld hl, MEM0 + ld b, 8 +__BOLD_LOOP: + ld a, (de) + ld c, a + rlca + or c + ld (hl), a + inc hl + inc de + djnz __BOLD_LOOP + pop hl + ld de, MEM0 + ret + + +__ITALIC: + push hl + ld hl, MEM0 + ex de, hl + ld bc, 8 + ldir + ld hl, MEM0 + srl (hl) + inc hl + srl (hl) + inc hl + srl (hl) + inc hl + inc hl + inc hl + sla (hl) + inc hl + sla (hl) + inc hl + sla (hl) + pop hl + ld de, MEM0 + ret + +PRINT_COMMA: + call __LOAD_S_POSN + ld a, e + and 16 + add a, 16 + +PRINT_TAB: + PROC + LOCAL LOOP, CONTINUE + + inc a + call __LOAD_S_POSN ; e = current row + ld d, a + ld a, e + cp 21h + jr nz, CONTINUE + ld e, -1 +CONTINUE: + ld a, d + inc e + sub e ; A = A - E + and 31 ; + ret z ; Already at position E + ld b, a +LOOP: + ld a, ' ' + call __PRINTCHAR + djnz LOOP + ret + ENDP + +PRINT_AT: ; CHanges cursor to ROW, COL + ; COL in A register + ; ROW in stack + + pop hl ; Ret address + ex (sp), hl ; callee H = ROW + ld l, a + ex de, hl + + call __IN_SCREEN + ret nc ; Return if out of screen + + jp __SAVE_S_POSN + + LOCAL __PRINT_COM + LOCAL __BOLD + LOCAL __BOLD_LOOP + LOCAL __ITALIC + LOCAL __PRINT_EOL1 + LOCAL __PRINT_EOL2 + LOCAL __PRINT_AT1 + LOCAL __PRINT_AT2 + LOCAL __PRINT_AT2_END + LOCAL __PRINT_BOLD + LOCAL __PRINT_BOLD2 + LOCAL __PRINT_ITA + LOCAL __PRINT_ITA2 + LOCAL __PRINT_INK + LOCAL __PRINT_PAP + LOCAL __PRINT_SET_STATE + LOCAL __PRINT_TABLE + LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 + +__PRINT_TABLE: ; Jump table for 0 .. 22 codes + + DW __PRINT_NOP ; 0 + DW __PRINT_NOP ; 1 + DW __PRINT_NOP ; 2 + DW __PRINT_NOP ; 3 + DW __PRINT_NOP ; 4 + DW __PRINT_NOP ; 5 + DW __PRINT_COM ; 6 COMMA + DW __PRINT_NOP ; 7 + DW __PRINT_DEL ; 8 DEL + DW __PRINT_NOP ; 9 + DW __PRINT_NOP ; 10 + DW __PRINT_NOP ; 11 + DW __PRINT_NOP ; 12 + DW __PRINT_0Dh ; 13 + DW __PRINT_BOLD ; 14 + DW __PRINT_ITA ; 15 + DW __PRINT_INK ; 16 + DW __PRINT_PAP ; 17 + DW __PRINT_FLA ; 18 + DW __PRINT_BRI ; 19 + DW __PRINT_INV ; 20 + DW __PRINT_OVR ; 21 + DW __PRINT_AT ; 22 AT + DW __PRINT_TAB ; 23 TAB + + ENDP + + +#line 124 "subrec.bas" +#line 1 "printstr.asm" + + + + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 5 "printstr.asm" + + ; PRINT command routine + ; Prints string pointed by HL + +PRINT_STR: +__PRINTSTR: ; __FASTCALL__ Entry to print_string + PROC + LOCAL __PRINT_STR_LOOP + LOCAL __PRINT_STR_END + + ld d, a ; Saves A reg (Flag) for later + + ld a, h + or l + ret z ; Return if the pointer is NULL + + push hl + + ld c, (hl) + inc hl + ld b, (hl) + inc hl ; BC = LEN(a$); HL = &a$ + +__PRINT_STR_LOOP: + ld a, b + or c + jr z, __PRINT_STR_END ; END if BC (counter = 0) + + ld a, (hl) + call __PRINTCHAR + inc hl + dec bc + jp __PRINT_STR_LOOP + +__PRINT_STR_END: + pop hl + ld a, d ; Recovers A flag + or a ; If not 0 this is a temporary string. Free it + ret z + jp __MEM_FREE ; Frees str from heap and return from there + +__PRINT_STR: + ; Fastcall Entry + ; It ONLY prints strings + ; HL = String start + ; BC = String length (Number of chars) + push hl ; Push str address for later + ld d, a ; Saves a FLAG + jp __PRINT_STR_LOOP + + ENDP + +#line 125 "subrec.bas" +#line 1 "printu32.asm" + +#line 1 "printi32.asm" + +#line 1 "printnum.asm" + + + + +__PRINTU_START: + PROC + + LOCAL __PRINTU_CONT + + ld a, b + or a + jp nz, __PRINTU_CONT + + ld a, '0' + jp __PRINT_DIGIT + + +__PRINTU_CONT: + pop af + push bc + call __PRINT_DIGIT + pop bc + djnz __PRINTU_CONT + ret + + ENDP + + +__PRINT_MINUS: ; PRINT the MINUS (-) sign. CALLER mus preserve registers + ld a, '-' + jp __PRINT_DIGIT + + __PRINT_DIGIT EQU __PRINTCHAR ; PRINTS the char in A register, and puts its attrs + + +#line 2 "printi32.asm" +#line 1 "neg32.asm" + +__ABS32: + bit 7, d + ret z + +__NEG32: ; Negates DEHL (Two's complement) + ld a, l + cpl + ld l, a + + ld a, h + cpl + ld h, a + + ld a, e + cpl + ld e, a + + ld a, d + cpl + ld d, a + + inc l + ret nz + + inc h + ret nz + + inc de + ret + +#line 3 "printi32.asm" +#line 1 "div32.asm" + + + + ; --------------------------------------------------------- +__DIVU32: ; 32 bit unsigned division + ; DEHL = Dividend, Stack Top = Divisor + ; OPERANDS P = Dividend, Q = Divisor => OPERATION => P / Q + ; + ; Changes A, BC DE HL B'C' D'E' H'L' + ; --------------------------------------------------------- + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + +__DIVU32START: ; Performs D'E'H'L' / HLDE + ; Now switch to DIVIDEND = B'C'BC / DIVISOR = D'E'DE (A / B) + push de ; push Lowpart(Q) + ex de, hl ; DE = HL + ld hl, 0 + exx + ld b, h + ld c, l + pop hl + push de + ex de, hl + ld hl, 0 ; H'L'HL = 0 + exx + pop bc ; Pop HightPart(B) => B = B'C'BC + exx + + ld a, 32 ; Loop count + +__DIV32LOOP: + sll c ; B'C'BC << 1 ; Output most left bit to carry + rl b + exx + rl c + rl b + exx + + adc hl, hl + exx + adc hl, hl + exx + + sbc hl,de + exx + sbc hl,de + exx + jp nc, __DIV32NOADD ; use JP inside a loop for being faster + + add hl, de + exx + adc hl, de + exx + dec bc + +__DIV32NOADD: + dec a + jp nz, __DIV32LOOP ; use JP inside a loop for being faster + ; At this point, quotient is stored in B'C'BC and the reminder in H'L'HL + + push hl + exx + pop de + ex de, hl ; D'E'H'L' = 32 bits modulus + push bc + exx + pop de ; DE = B'C' + ld h, b + ld l, c ; DEHL = quotient D'E'H'L' = Modulus + + ret ; DEHL = quotient, D'E'H'L' = Modulus + + + +__MODU32: ; 32 bit modulus for 32bit unsigned division + ; DEHL = Dividend, Stack Top = Divisor (DE, HL) + + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + + call __DIVU32START ; At return, modulus is at D'E'H'L' + +__MODU32START: + + exx + push de + push hl + + exx + pop hl + pop de + + ret + + +__DIVI32: ; 32 bit signed division + ; DEHL = Dividend, Stack Top = Divisor + ; A = Dividend, B = Divisor => A / B + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + +__DIVI32START: + exx + ld a, d ; Save sign + ex af, af' + bit 7, d ; Negative? + call nz, __NEG32 ; Negates DEHL + + exx ; Now works with H'L'D'E' + ex af, af' + xor h + ex af, af' ; Stores sign of the result for later + + bit 7, h ; Negative? + ex de, hl ; HLDE = DEHL + call nz, __NEG32 + ex de, hl + + call __DIVU32START + ex af, af' ; Recovers sign + and 128 ; positive? + ret z + + jp __NEG32 ; Negates DEHL and returns from there + + +__MODI32: ; 32bits signed division modulus + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + + call __DIVI32START + jp __MODU32START + +#line 4 "printi32.asm" + + + +__PRINTI32: + ld a, d + or a + jp p, __PRINTU32 + + call __PRINT_MINUS + call __NEG32 + +__PRINTU32: + PROC + LOCAL __PRINTU_LOOP + + ld b, 0 ; Counter + +__PRINTU_LOOP: + ld a, h + or l + or d + or e + jp z, __PRINTU_START + + push bc + + ld bc, 0 + push bc + ld bc, 10 + push bc ; Push 00 0A (10 Dec) into the stack = divisor + + call __DIVU32 ; Divides by 32. D'E'H'L' contains modulo (L' since < 10) + pop bc + + exx + ld a, l + or '0' ; Stores ASCII digit (must be print in reversed order) + push af + exx + inc b + jp __PRINTU_LOOP ; Uses JP in loops + + ENDP + +#line 2 "printu32.asm" + +#line 126 "subrec.bas" +#line 1 "printu8.asm" + +#line 1 "printi8.asm" + + +#line 1 "div8.asm" + + ; -------------------------------- +__DIVU8: ; 8 bit unsigned integer division + ; Divides (Top of stack, High Byte) / A + pop hl ; -------------------------------- + ex (sp), hl ; CALLEE + +__DIVU8_FAST: ; Does A / H + ld l, h + ld h, a ; At this point do H / L + + ld b, 8 + xor a ; A = 0, Carry Flag = 0 + +__DIV8LOOP: + sla h + rla + cp l + jr c, __DIV8NOSUB + sub l + inc h + +__DIV8NOSUB: + djnz __DIV8LOOP + + ld l, a ; save remainder + ld a, h ; + + ret ; a = Quotient, + + + ; -------------------------------- +__DIVI8: ; 8 bit signed integer division Divides (Top of stack) / A + pop hl ; -------------------------------- + ex (sp), hl + +__DIVI8_FAST: + ld e, a ; store operands for later + ld c, h + + or a ; negative? + jp p, __DIV8A + neg ; Make it positive + +__DIV8A: + ex af, af' + ld a, h + or a + jp p, __DIV8B + neg + ld h, a ; make it positive + +__DIV8B: + ex af, af' + + call __DIVU8_FAST + + ld a, c + xor l ; bit 7 of A = 1 if result is negative + + ld a, h ; Quotient + ret p ; return if positive + + neg + ret + + +__MODU8: ; 8 bit module. REturns A mod (Top of stack) (unsigned operands) + pop hl + ex (sp), hl ; CALLEE + +__MODU8_FAST: ; __FASTCALL__ entry + call __DIVU8_FAST + ld a, l ; Remainder + + ret ; a = Modulus + + +__MODI8: ; 8 bit module. REturns A mod (Top of stack) (For singed operands) + pop hl + ex (sp), hl ; CALLEE + +__MODI8_FAST: ; __FASTCALL__ entry + call __DIVI8_FAST + ld a, l ; remainder + + ret ; a = Modulus + +#line 3 "printi8.asm" + +__PRINTI8: ; Prints an 8 bits number in Accumulator (A) + ; Converts 8 to 32 bits + or a + jp p, __PRINTU8 + + push af + call __PRINT_MINUS + pop af + neg + +__PRINTU8: + PROC + + LOCAL __PRINTU_LOOP + + ld b, 0 ; Counter + +__PRINTU_LOOP: + or a + jp z, __PRINTU_START + + push bc + ld h, 10 + call __DIVU8_FAST ; Divides by 10. D'E'H'L' contains modulo (L' since < 10) + pop bc + + ld a, l + or '0' ; Stores ASCII digit (must be print in reversed order) + push af + ld a, h + inc b + jp __PRINTU_LOOP ; Uses JP in loops + + ENDP + +#line 2 "printu8.asm" + +#line 127 "subrec.bas" +#line 1 "sub32.asm" + + ; SUB32 + ; Perform TOP of the stack - DEHL + ; Pops operand out of the stack (CALLEE) + ; and returns result in DEHL. Carry an Z are set correctly + +__SUB32: + exx + pop bc ; saves return address in BC' + exx + + or a ; clears carry flag + ld b, h ; Operands come reversed => BC <- HL, HL = HL - BC + ld c, l + pop hl + sbc hl, bc + ex de, hl + + ld b, h ; High part (DE) now in HL. Repeat operation + ld c, l + pop hl + sbc hl, bc + ex de, hl ; DEHL now has de 32 bit result + + exx + push bc ; puts return address back + exx + ret +#line 128 "subrec.bas" + +ZXBASIC_USER_DATA: +_result: + DEFB 01h + DEFB 00h + DEFB 00h + DEFB 00h +_x: + DEFB 00 +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/subrec.bas b/tests/functional/subrec.bas new file mode 100644 index 000000000..cba3f8ba9 --- /dev/null +++ b/tests/functional/subrec.bas @@ -0,0 +1,20 @@ +REM Factorial recursive test + +DIM result as ulong = 1 + +sub fact(x as ulong) + if x < 2 then + return + end if + + result = result * x + fact(x - 1) +end sub + +cls +for x = 1 To 10: + result = 1 + fact(x) + print "Fact ("; x; ") = "; result +next x + From 3f27b39c2d3a9acffb2ff1afd5b57194a1027ee7 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 27 Nov 2017 13:19:21 +0100 Subject: [PATCH 131/247] revert last change to follow the community After consulting with other people in the BASIC community, the last change has been reverted. So an IF is multiline only if it has a carriage return just after the THEN. Also adds more tests cases. Finally bugfix a missing sintactic case. --- .../{ifthencoendif.asm => ifcoendif.asm} | 4 +- tests/functional/ifcoendif.bas | 4 ++ .../{ifthencoendif2.asm => ifcoendif1.asm} | 11 ++--- tests/functional/ifcoendif1.bas | 4 ++ tests/functional/ifcoendif2.asm | 45 +++++++++++++++++++ tests/functional/ifcoendif2.bas | 4 ++ tests/functional/ifempty0.asm | 37 +++++++++++++++ tests/functional/ifthencoendif2.bas | 2 +- tests/functional/test_errmsg.txt | 2 +- zxbparser.py | 6 +-- 10 files changed, 103 insertions(+), 16 deletions(-) rename tests/functional/{ifthencoendif.asm => ifcoendif.asm} (96%) create mode 100644 tests/functional/ifcoendif.bas rename tests/functional/{ifthencoendif2.asm => ifcoendif1.asm} (90%) create mode 100644 tests/functional/ifcoendif1.bas create mode 100644 tests/functional/ifcoendif2.asm create mode 100644 tests/functional/ifcoendif2.bas create mode 100644 tests/functional/ifempty0.asm diff --git a/tests/functional/ifthencoendif.asm b/tests/functional/ifcoendif.asm similarity index 96% rename from tests/functional/ifthencoendif.asm rename to tests/functional/ifcoendif.asm index c95c9230a..272f7d136 100644 --- a/tests/functional/ifthencoendif.asm +++ b/tests/functional/ifcoendif.asm @@ -10,7 +10,7 @@ __START_PROGRAM: add hl, sp ld (__CALL_BACK__), hl ei - ld h, 0 + ld h, 1 ld a, (_a) call __LTI8 or a @@ -61,7 +61,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 27 "ifthencoendif.bas" +#line 27 "ifcoendif.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/ifcoendif.bas b/tests/functional/ifcoendif.bas new file mode 100644 index 000000000..d3c8a9d17 --- /dev/null +++ b/tests/functional/ifcoendif.bas @@ -0,0 +1,4 @@ +DIM a as Byte + +IF a < 1 THEN: LET a = a + 1: + diff --git a/tests/functional/ifthencoendif2.asm b/tests/functional/ifcoendif1.asm similarity index 90% rename from tests/functional/ifthencoendif2.asm rename to tests/functional/ifcoendif1.asm index 34cde75ad..3a064b5bc 100644 --- a/tests/functional/ifthencoendif2.asm +++ b/tests/functional/ifcoendif1.asm @@ -10,19 +10,14 @@ __START_PROGRAM: add hl, sp ld (__CALL_BACK__), hl ei - ld h, 0 + ld h, 1 ld a, (_a) call __LTI8 or a - jp z, __LABEL0 + jp z, __LABEL1 ld a, (_a) inc a ld (_a), a - jp __LABEL1 -__LABEL0: - ld a, (_a) - dec a - ld (_a), a __LABEL1: ld hl, 0 ld b, h @@ -66,7 +61,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 32 "ifthencoendif2.bas" +#line 27 "ifcoendif1.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/ifcoendif1.bas b/tests/functional/ifcoendif1.bas new file mode 100644 index 000000000..d3c8a9d17 --- /dev/null +++ b/tests/functional/ifcoendif1.bas @@ -0,0 +1,4 @@ +DIM a as Byte + +IF a < 1 THEN: LET a = a + 1: + diff --git a/tests/functional/ifcoendif2.asm b/tests/functional/ifcoendif2.asm new file mode 100644 index 000000000..9b17225e1 --- /dev/null +++ b/tests/functional/ifcoendif2.asm @@ -0,0 +1,45 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld h, 1 + ld a, (_a) + cp h + jp nc, __LABEL1 + ld a, (_a) + inc a + ld (_a), a +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifcoendif2.bas b/tests/functional/ifcoendif2.bas new file mode 100644 index 000000000..e14670944 --- /dev/null +++ b/tests/functional/ifcoendif2.bas @@ -0,0 +1,4 @@ +DIM a as UByte + +IF a < 1 THEN: LET a = a + 1 + diff --git a/tests/functional/ifempty0.asm b/tests/functional/ifempty0.asm new file mode 100644 index 000000000..49d4ccd19 --- /dev/null +++ b/tests/functional/ifempty0.asm @@ -0,0 +1,37 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_i: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifthencoendif2.bas b/tests/functional/ifthencoendif2.bas index 902b6673b..584d45a2c 100644 --- a/tests/functional/ifthencoendif2.bas +++ b/tests/functional/ifthencoendif2.bas @@ -1,7 +1,7 @@ DIM a as Byte -IF a < 0 THEN: +IF a < 0 THEN LET a = a + 1 ELSE: LET a = a - 1 diff --git a/tests/functional/test_errmsg.txt b/tests/functional/test_errmsg.txt index 08d953590..20ccea4e4 100644 --- a/tests/functional/test_errmsg.txt +++ b/tests/functional/test_errmsg.txt @@ -101,7 +101,7 @@ ifempty1.bas:3: warning: Useless empty IF ignored >>> process_file('ifempty5.bas') ifempty5.bas:3: warning: Condition is always True >>> process_file('ifempty0.bas') -ifempty0.bas:5: Unexpected end of file +ifempty0.bas:3: warning: Useless empty IF ignored >>> process_file('forempty.bas') forempty.bas:4: warning: STEP value is 0 and FOR might loop forever >>> process_file('fornextopt.bas') diff --git a/zxbparser.py b/zxbparser.py index 7d96fa84a..7347872a9 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -1156,7 +1156,6 @@ def p_go(p): # region [IF sentence] def p_if_sentence(p): """ statement : if_then_part NEWLINE program_co endif - | if_then_part CO program_co endif | if_then_part NEWLINE endif """ cond_ = p[1] @@ -1197,6 +1196,7 @@ def p_single_line_if(p): """ if_inline : if_then_part statements %prec ID | if_then_part co_statements_co %prec NEWLINE | if_then_part statements_co %prec NEWLINE + | if_then_part co_statements %prec ID """ cond_ = p[1] stat_ = p[2] @@ -1255,12 +1255,11 @@ def p_elseif_elseiflist(p): def p_else_part_endif(p): """ else_part_inline : ELSE NEWLINE program_co endif - | ELSE CO program_co endif | ELSE NEWLINE endif | ELSE statements_co endif | ELSE co_statements_co endif """ - if p[2] in ('\n', ':'): + if p[2] == '\n': p[0] = [make_nop(), p[3]] if len(p) == 4 else [p[3], p[4]] else: p[0] = [p[2], p[3]] @@ -1307,7 +1306,6 @@ def p_if_inline(p): def p_if_else(p): """ statement : if_then_part NEWLINE program_co else_part - | if_then_part CO program_co else_part """ cond_ = p[1] then_ = p[3] From 23a74b322fc183ca43c1484fb8accdee9dd2b3cf Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 28 Nov 2017 21:58:01 +0100 Subject: [PATCH 132/247] update PONG example --- examples/pong.bas | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/examples/pong.bas b/examples/pong.bas index b31e522a5..bf9e5d09b 100644 --- a/examples/pong.bas +++ b/examples/pong.bas @@ -61,7 +61,8 @@ 95 REM Draws Ball. Begin of GAME LOOP 96 LET xx = x: LET yy = y: LET oldX = x: LET oldY = y: GOSUB 2000 100 LET x = x + dx -110 IF x < minX THEN LET x = minX: LET dx = -dx: BEEP 0.02,20 +110 IF x < minX THEN + LET x = minX: LET dx = -dx: BEEP 0.02,20 LET py = coords(0, 1) IF py > y OR py + h <= y THEN REM Player 2 wins 1 Point @@ -83,7 +84,8 @@ delay = dSlow END IF END IF - ELSEIF x > maxX THEN LET x = maxX: LET dx = -dx: BEEP 0.02,20 + ELSEIF x > maxX THEN + LET x = maxX: LET dx = -dx: BEEP 0.02,20 LET py = coords(1, 1) IF py > y OR py + h <= y THEN REM Player 1 wins 1 Point @@ -108,13 +110,15 @@ END IF 120 LET y = y + dy -130 IF y < minY THEN LET y = minY: BEEP 0.02,10: LET dy = -dy - ELSEIF y > maxY THEN LET y = maxY: BEEP 0.02,10: LET dy = -dy +130 IF y < minY THEN + LET y = minY: BEEP 0.02,10: LET dy = -dy + ELSEIF y > maxY THEN + LET y = maxY: BEEP 0.02,10: LET dy = -dy END IF 140 REM Checks if computer must move 150 LET px = coords(comp, 0): LET py = coords(comp, 1) -160 IF py > y AND RND > diff THEN: REM Must go up +160 IF py > y AND RND > diff THEN REM Must go up LET p = comp GOSUB 1500: REM Updates player padel (up) ELSEIF py + h - 1 < y AND RND > diff THEN @@ -124,10 +128,10 @@ 200 REM Checks if Player moves ("4", "3") 210 LET px = coords(user, 0): LET py = coords(user, 1) -220 if py > minY AND (INKEY$ = "4" OR INKEY$ = "q") THEN: REM Must go up +220 if py > minY AND (INKEY$ = "4" OR INKEY$ = "q") THEN REM Must go up LET p = user GOSUB 1500: REM Updates player padel (up) - ELSEIF py + h < maxY AND (INKEY$ = "3" OR INKEY$ = "a") THEN: REM Must go down + ELSEIF py + h < maxY AND (INKEY$ = "3" OR INKEY$ = "a") THEN REM Must go down LET p = user GOSUB 1600: REM Updates player padel (down) END IF @@ -189,7 +193,7 @@ 3000 REM Prints SCORES 3010 FOR player = 0 TO 1 3020 LET atY = minY + 1: LET atX = minX + 4 + player * (maxX - minX) / 4: LET sc = score(player) -3030 IF sc < 10 THEN: REM erases left digit +3030 IF sc < 10 THEN REM erases left digit FOR i = 0 TO 2: PRINT OVER 0; AT atY + i, atX; " ";:NEXT i ELSE LET NUM = sc / 10: REM Left digit From 3b7900a9b33a887b520f9008337f52166a9af6fd Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 28 Nov 2017 22:46:33 +0100 Subject: [PATCH 133/247] update input.bas library for new syntax --- library/input.bas | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/library/input.bas b/library/input.bas index 0e50f990e..54e61f48a 100644 --- a/library/input.bas +++ b/library/input.bas @@ -39,21 +39,18 @@ FUNCTION input(MaxLen AS UINTEGER) AS STRING PRIVATEInputHideCursor() - IF LastK = 12 THEN: - IF LEN(result$) THEN : REM "Del" key code is 12 - IF LEN(result$) = 1 THEN: + IF LastK = 12 THEN + IF LEN(result$) THEN REM "Del" key code is 12 + IF LEN(result$) = 1 THEN LET result$ = "" ELSE LET result$ = result$( TO LEN(result$) - 2) END IF PRINT CHR$(8); END IF - - ELSE IF LastK >= CODE(" ") AND LEN(result$) < MaxLen THEN + ELSEIF LastK >= CODE(" ") AND LEN(result$) < MaxLen THEN LET result$ = result$ + CHR$(LastK) PRINT CHR$(LastK); - END IF - END IF LOOP UNTIL LastK = 13 : REM "Enter" key code is 13 From 98aa173ea9342526be6dd620afd3385ede570452 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 28 Nov 2017 22:46:57 +0100 Subject: [PATCH 134/247] add support for more IF ENDIF constructs --- tests/functional/ifthencosntcoendif.asm | 45 +++++++++++ tests/functional/ifthencosntcoendif.bas | 6 ++ tests/functional/ifthenlblsntcoendif.asm | 46 +++++++++++ tests/functional/ifthenlblsntcoendif.bas | 6 ++ tests/functional/ifthensntcoelsecocoendif.asm | 78 +++++++++++++++++++ tests/functional/ifthensntcoelsecocoendif.bas | 8 ++ tests/functional/ifthensntcoelsecoendif.asm | 78 +++++++++++++++++++ tests/functional/ifthensntcoelsecoendif.bas | 8 ++ tests/functional/ifthensntcoelselblco.asm | 52 +++++++++++++ tests/functional/ifthensntcoelselblco.bas | 8 ++ tests/functional/ifthensntcoelselblcoco.asm | 52 +++++++++++++ tests/functional/ifthensntcoelselblcoco.bas | 8 ++ tests/functional/ifthensntcoendif.asm | 45 +++++++++++ tests/functional/ifthensntcoendif.bas | 6 ++ zxbparser.py | 20 ++++- 15 files changed, 464 insertions(+), 2 deletions(-) create mode 100644 tests/functional/ifthencosntcoendif.asm create mode 100644 tests/functional/ifthencosntcoendif.bas create mode 100644 tests/functional/ifthenlblsntcoendif.asm create mode 100644 tests/functional/ifthenlblsntcoendif.bas create mode 100644 tests/functional/ifthensntcoelsecocoendif.asm create mode 100644 tests/functional/ifthensntcoelsecocoendif.bas create mode 100644 tests/functional/ifthensntcoelsecoendif.asm create mode 100644 tests/functional/ifthensntcoelsecoendif.bas create mode 100644 tests/functional/ifthensntcoelselblco.asm create mode 100644 tests/functional/ifthensntcoelselblco.bas create mode 100644 tests/functional/ifthensntcoelselblcoco.asm create mode 100644 tests/functional/ifthensntcoelselblcoco.bas create mode 100644 tests/functional/ifthensntcoendif.asm create mode 100644 tests/functional/ifthensntcoendif.bas diff --git a/tests/functional/ifthencosntcoendif.asm b/tests/functional/ifthencosntcoendif.asm new file mode 100644 index 000000000..23c038c6d --- /dev/null +++ b/tests/functional/ifthencosntcoendif.asm @@ -0,0 +1,45 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld h, 0 + ld a, (_a) + cp h + jp nc, __LABEL1 + ld a, (_a) + inc a + ld (_a), a +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifthencosntcoendif.bas b/tests/functional/ifthencosntcoendif.bas new file mode 100644 index 000000000..897d57f82 --- /dev/null +++ b/tests/functional/ifthencosntcoendif.bas @@ -0,0 +1,6 @@ + +DIM a as UByte + +IF a < 0 THEN + :LET a = a + 1: END IF + diff --git a/tests/functional/ifthenlblsntcoendif.asm b/tests/functional/ifthenlblsntcoendif.asm new file mode 100644 index 000000000..831b04f9c --- /dev/null +++ b/tests/functional/ifthenlblsntcoendif.asm @@ -0,0 +1,46 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld h, 0 + ld a, (_a) + cp h + jp nc, __LABEL1 +__LABEL__10: + ld a, (_a) + inc a + ld (_a), a +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifthenlblsntcoendif.bas b/tests/functional/ifthenlblsntcoendif.bas new file mode 100644 index 000000000..341f98d7c --- /dev/null +++ b/tests/functional/ifthenlblsntcoendif.bas @@ -0,0 +1,6 @@ + +DIM a as UByte + +IF a < 0 THEN +10 LET a = a + 1: END IF + diff --git a/tests/functional/ifthensntcoelsecocoendif.asm b/tests/functional/ifthensntcoelsecocoendif.asm new file mode 100644 index 000000000..ed571ee79 --- /dev/null +++ b/tests/functional/ifthensntcoelsecocoendif.asm @@ -0,0 +1,78 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld h, 1 + ld a, (_a) + call __LTI8 + or a + jp z, __LABEL0 + ld a, (_a) + inc a + ld (_a), a + jp __LABEL1 +__LABEL0: + ld a, (_a) + dec a + ld (_a), a +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "lti8.asm" + +#line 1 "lei8.asm" + +__LEI8: ; Signed <= comparison for 8bit int + ; A <= H (registers) + PROC + LOCAL checkParity + sub h + jr nz, __LTI + inc a + ret + +__LTI8: ; Test 8 bit values A < H + sub h + +__LTI: ; Generic signed comparison + jp po, checkParity + xor 0x80 +checkParity: + ld a, 0 ; False + ret p + inc a ; True + ret + ENDP +#line 2 "lti8.asm" +#line 32 "ifthensntcoelsecocoendif.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifthensntcoelsecocoendif.bas b/tests/functional/ifthensntcoelsecocoendif.bas new file mode 100644 index 000000000..9f0fd22e3 --- /dev/null +++ b/tests/functional/ifthensntcoelsecocoendif.bas @@ -0,0 +1,8 @@ + +DIM a as Byte + +IF a < 1 THEN + LET a = a + 1 +ELSE + :LET a = a - 1: END IF + diff --git a/tests/functional/ifthensntcoelsecoendif.asm b/tests/functional/ifthensntcoelsecoendif.asm new file mode 100644 index 000000000..27e56de5a --- /dev/null +++ b/tests/functional/ifthensntcoelsecoendif.asm @@ -0,0 +1,78 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld h, 1 + ld a, (_a) + call __LTI8 + or a + jp z, __LABEL0 + ld a, (_a) + inc a + ld (_a), a + jp __LABEL1 +__LABEL0: + ld a, (_a) + dec a + ld (_a), a +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "lti8.asm" + +#line 1 "lei8.asm" + +__LEI8: ; Signed <= comparison for 8bit int + ; A <= H (registers) + PROC + LOCAL checkParity + sub h + jr nz, __LTI + inc a + ret + +__LTI8: ; Test 8 bit values A < H + sub h + +__LTI: ; Generic signed comparison + jp po, checkParity + xor 0x80 +checkParity: + ld a, 0 ; False + ret p + inc a ; True + ret + ENDP +#line 2 "lti8.asm" +#line 32 "ifthensntcoelsecoendif.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifthensntcoelsecoendif.bas b/tests/functional/ifthensntcoelsecoendif.bas new file mode 100644 index 000000000..63c83b050 --- /dev/null +++ b/tests/functional/ifthensntcoelsecoendif.bas @@ -0,0 +1,8 @@ + +DIM a as Byte + +IF a < 1 THEN + LET a = a + 1 +ELSE + LET a = a - 1: END IF + diff --git a/tests/functional/ifthensntcoelselblco.asm b/tests/functional/ifthensntcoelselblco.asm new file mode 100644 index 000000000..f7a857f25 --- /dev/null +++ b/tests/functional/ifthensntcoelselblco.asm @@ -0,0 +1,52 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld h, 0 + ld a, (_a) + cp h + jp nc, __LABEL0 +__LABEL__10: + ld a, (_a) + inc a + ld (_a), a + jp __LABEL1 +__LABEL0: +__LABEL__30: + ld a, (_a) + dec a + ld (_a), a +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifthensntcoelselblco.bas b/tests/functional/ifthensntcoelselblco.bas new file mode 100644 index 000000000..3de62008e --- /dev/null +++ b/tests/functional/ifthensntcoelselblco.bas @@ -0,0 +1,8 @@ + +DIM a as UByte + +IF a < 0 THEN +10 LET a = a + 1 +ELSE +30 LET a = a - 1: END IF + diff --git a/tests/functional/ifthensntcoelselblcoco.asm b/tests/functional/ifthensntcoelselblcoco.asm new file mode 100644 index 000000000..f7a857f25 --- /dev/null +++ b/tests/functional/ifthensntcoelselblcoco.asm @@ -0,0 +1,52 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld h, 0 + ld a, (_a) + cp h + jp nc, __LABEL0 +__LABEL__10: + ld a, (_a) + inc a + ld (_a), a + jp __LABEL1 +__LABEL0: +__LABEL__30: + ld a, (_a) + dec a + ld (_a), a +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifthensntcoelselblcoco.bas b/tests/functional/ifthensntcoelselblcoco.bas new file mode 100644 index 000000000..4f5477b18 --- /dev/null +++ b/tests/functional/ifthensntcoelselblcoco.bas @@ -0,0 +1,8 @@ + +DIM a as UByte + +IF a < 0 THEN +10 LET a = a + 1 +ELSE +30 :LET a = a - 1: END IF + diff --git a/tests/functional/ifthensntcoendif.asm b/tests/functional/ifthensntcoendif.asm new file mode 100644 index 000000000..23c038c6d --- /dev/null +++ b/tests/functional/ifthensntcoendif.asm @@ -0,0 +1,45 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld h, 0 + ld a, (_a) + cp h + jp nc, __LABEL1 + ld a, (_a) + inc a + ld (_a), a +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifthensntcoendif.bas b/tests/functional/ifthensntcoendif.bas new file mode 100644 index 000000000..56b84f255 --- /dev/null +++ b/tests/functional/ifthensntcoendif.bas @@ -0,0 +1,6 @@ + +DIM a as UByte + +IF a < 0 THEN + LET a = a + 1: END IF + diff --git a/zxbparser.py b/zxbparser.py index 7347872a9..eb2797f43 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -1157,9 +1157,16 @@ def p_go(p): def p_if_sentence(p): """ statement : if_then_part NEWLINE program_co endif | if_then_part NEWLINE endif + | if_then_part NEWLINE statements_co endif + | if_then_part NEWLINE co_statements_co endif + | if_then_part NEWLINE LABEL statements_co endif """ cond_ = p[1] - if len(p) == 5: + if len(p) == 6: + lbl = make_label(p[3], p.lineno(3)) + stat_ = make_block(lbl, p[4]) + endif_ = p[5] + elif len(p) == 5: stat_ = p[3] endif_ = p[4] else: @@ -1255,12 +1262,21 @@ def p_elseif_elseiflist(p): def p_else_part_endif(p): """ else_part_inline : ELSE NEWLINE program_co endif + | ELSE NEWLINE statements_co endif + | ELSE NEWLINE co_statements_co endif | ELSE NEWLINE endif + | ELSE NEWLINE LABEL statements_co endif + | ELSE NEWLINE LABEL co_statements_co endif | ELSE statements_co endif | ELSE co_statements_co endif """ if p[2] == '\n': - p[0] = [make_nop(), p[3]] if len(p) == 4 else [p[3], p[4]] + if len(p) == 4: + p[0] = [make_nop(), p[3]] + elif len(p) == 6: + p[0] = [make_label(p[3], p.lineno(3)), p[4], p[5]] + else: + p[0] = [p[3], p[4]] else: p[0] = [p[2], p[3]] From 1ce5b3b226047d6e44275058e930436e8299374d Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 29 Nov 2017 22:01:28 +0100 Subject: [PATCH 135/247] bugfix: incorrect asm preproc for \ When defining a multiline macro, like # define mymacro \ line1 \ line2 the trailing \ should not be output. Fixed. --- tests/functional/prepro35.out | 6 ------ tests/functional/prepro80.bi | 11 +++++++++++ tests/functional/prepro80.out | 12 ++++++++++++ zxbpplex.py | 3 ++- 4 files changed, 25 insertions(+), 7 deletions(-) delete mode 100644 tests/functional/prepro35.out create mode 100644 tests/functional/prepro80.bi create mode 100644 tests/functional/prepro80.out diff --git a/tests/functional/prepro35.out b/tests/functional/prepro35.out deleted file mode 100644 index f1e50096b..000000000 --- a/tests/functional/prepro35.out +++ /dev/null @@ -1,6 +0,0 @@ -#line 1 "prepro35.bi" -asm - ld a, \ ; test - 5 -end asm - diff --git a/tests/functional/prepro80.bi b/tests/functional/prepro80.bi new file mode 100644 index 000000000..ee3c621b7 --- /dev/null +++ b/tests/functional/prepro80.bi @@ -0,0 +1,11 @@ +REM simple WaitRetrace macro + +#ifndef waitretrace +#define waitretrace 'REM Retrace \ + asm \ + halt \ + halt \ + end asm + +#endif + diff --git a/tests/functional/prepro80.out b/tests/functional/prepro80.out new file mode 100644 index 000000000..c2855c979 --- /dev/null +++ b/tests/functional/prepro80.out @@ -0,0 +1,12 @@ +#line 1 "prepro80.bi" + + + + + asm + halt + halt + end asm + +#line 11 "prepro80.bi" + diff --git a/zxbpplex.py b/zxbpplex.py index 55388bf35..a5de6149f 100755 --- a/zxbpplex.py +++ b/zxbpplex.py @@ -87,8 +87,9 @@ def t_asm_asmEnd(self, t): return t def t_asm_CONTINUE(self, t): - r'[\\_]([ \t]*;.*)?\r?\n' # TODO: remove _ from line continuation in ASM contexts + r'[\\_]\r?\n' t.lexer.lineno += 1 + t.value = t.value[1:] return t def t_asm_COMMENT(self, t): From 64f8cab79b4a051cb9f152bf468c3dff3c22ac27 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 1 Dec 2017 00:09:37 +0100 Subject: [PATCH 136/247] bugfix: fix crash in optimizer --- arch/zx48k/optimizer.py | 2 + tests/functional/opt3_haplo05.asm | 171 ++++++++++++++++++++++++++++++ tests/functional/opt3_haplo05.bas | 28 +++++ 3 files changed, 201 insertions(+) create mode 100644 tests/functional/opt3_haplo05.asm create mode 100644 tests/functional/opt3_haplo05.bas diff --git a/arch/zx48k/optimizer.py b/arch/zx48k/optimizer.py index 51b2f481f..e7c44214d 100644 --- a/arch/zx48k/optimizer.py +++ b/arch/zx48k/optimizer.py @@ -396,6 +396,8 @@ def reset(self): def set(self, r, val): is_num = is_number(val) + if is_num: + val = str(val) if is_num and self.getv(r) == valnum(val) & 0xFFFF: return # The register already contains it value diff --git a/tests/functional/opt3_haplo05.asm b/tests/functional/opt3_haplo05.asm new file mode 100644 index 000000000..3426200a7 --- /dev/null +++ b/tests/functional/opt3_haplo05.asm @@ -0,0 +1,171 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld a, 4 + ld (31744), a + ld a, 83 + ld hl, (_dataSprite) + ld (hl), a + ld de, 11 + add hl, de + push hl + ld hl, (_dataSprite) + ld de, 4 + add hl, de + ld a, (hl) + ld h, 6 + call __MUL8_FAST + pop hl + ld (hl), a + ld hl, (_dataSprite) + ld de, 12 + add hl, de + push hl + ld hl, (_dataSprite) + ld de, 5 + add hl, de + ld a, (hl) + pop hl + add a, a + add a, a + ld (hl), a + ld hl, (_dataSprite) + ld de, 17 + add hl, de + ld de, 56978 + ld (hl), e + inc hl + ld (hl), d + ld hl, (_dataSprite) + ld de, 30 + add hl, de + push hl + ld hl, (_dataSprite) + ld de, 8 + add hl, de + ld a, (hl) + pop hl + ld (hl), a + ld hl, 0 + ld (31748), hl + ld hl, (_dataSprite) + ld de, 6 + add hl, de + xor a + ld (hl), a + ld hl, (_dataSprite) + ld de, 7 + add hl, de + xor a + ld (hl), a + ld hl, (_dataSprite) + ld de, 8 + add hl, de + xor a + ld (hl), a + ld hl, (_dataSprite) + ld de, 21 + add hl, de + xor a + ld (hl), a + ld hl, (_dataSprite) + ld de, 22 + add hl, de + xor a + ld (hl), a + ld hl, (_dataSprite) + ld de, 23 + add hl, de + xor a + ld (hl), a + ld hl, (_dataSprite) + ld de, 24 + add hl, de + xor a + ld (hl), a + ld bc, 0 +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + pop iy + pop ix + exx + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "mul8.asm" + +__MUL8: ; Performs 8bit x 8bit multiplication + PROC + + ;LOCAL __MUL8A + LOCAL __MUL8LOOP + LOCAL __MUL8B + ; 1st operand (byte) in A, 2nd operand into the stack (AF) + pop hl ; return address + ex (sp), hl ; CALLE convention + +;;__MUL8_FAST: ; __FASTCALL__ entry + ;; ld e, a + ;; ld d, 0 + ;; ld l, d + ;; + ;; sla h + ;; jr nc, __MUL8A + ;; ld l, e + ;; +;;__MUL8A: + ;; + ;; ld b, 7 +;;__MUL8LOOP: + ;; add hl, hl + ;; jr nc, __MUL8B + ;; + ;; add hl, de + ;; +;;__MUL8B: + ;; djnz __MUL8LOOP + ;; + ;; ld a, l ; result = A and HL (Truncate to lower 8 bits) + +__MUL8_FAST: ; __FASTCALL__ entry, a = a * h (8 bit mul) and Carry + + ld b, 8 + ld l, a + xor a + +__MUL8LOOP: + add a, a ; a *= 2 + sla l + jp nc, __MUL8B + add a, h + +__MUL8B: + djnz __MUL8LOOP + + ret ; result = HL + ENDP + +#line 98 "opt3_haplo05.bas" + +ZXBASIC_USER_DATA: +_dataSprite: + DEFB 00, 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/opt3_haplo05.bas b/tests/functional/opt3_haplo05.bas new file mode 100644 index 000000000..034ab1db1 --- /dev/null +++ b/tests/functional/opt3_haplo05.bas @@ -0,0 +1,28 @@ +Dim dataSprite,dw1,dw2,dw3,tB as Uinteger + +const enemiSprites as Uinteger= 49152 +const enemiBullets as Uinteger =63872 +const dirGraficoHuevo as Uinteger=enemiSprites+(91*86) +const dirGraficoBoom as Uinteger=enemiSprites+(97*86) + +const tablaSprites as Uinteger=30720 +const bulletToloStatus as UInteger= tablaSprites+1024 +const bulletToloCol as UInteger= tablaSprites+1024+4 +const bulletToloFila as UInteger= tablaSprites+1024+5 +const bulletToloFace as UInteger= tablaSprites+1024+8 + +poke bulletToloStatus,%00000100 +poke (dataSprite), %01010011 +poke (dataSprite+11),peek ((dataSprite+4))*6 +poke (dataSprite+12),peek ((dataSprite+5))*4 +poke UInteger (dataSprite+17),dirGraficoHuevo +poke (dataSprite+30),peek ((dataSprite+8)) +poke UInteger bulletToloCol,0 + +poke (dataSprite+6),0 +poke (dataSprite+7),0 +poke (dataSprite+8),0 +poke (dataSprite+21),0 +poke (dataSprite+22),0 +poke (dataSprite+23),0 +poke (dataSprite+24),0 From a26b299c5aa710df691babf249260ac2116fa229 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 1 Dec 2017 20:04:28 +0100 Subject: [PATCH 137/247] bugfix: potential crash on windows line endings --- tests/functional/ifcrash.asm | 526 +++++++++++++++++++++++++++++++++++ tests/functional/ifcrash.bas | 12 + zxblex.py | 3 +- 3 files changed, 540 insertions(+), 1 deletion(-) create mode 100644 tests/functional/ifcrash.asm create mode 100755 tests/functional/ifcrash.bas diff --git a/tests/functional/ifcrash.asm b/tests/functional/ifcrash.asm new file mode 100644 index 000000000..06fcb91c0 --- /dev/null +++ b/tests/functional/ifcrash.asm @@ -0,0 +1,526 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld a, (_KEYSPACE) + ld de, (_KEYSPACE + 1) + ld bc, (_KEYSPACE + 3) + ld a, c + or l + or h + or e + or d + jp z, __LABEL0 + ld hl, _keyspacepressed + 4 + call __FP_PUSH_REV + ld a, 000h + ld de, 00000h + ld bc, 00000h + call __EQF + or a + jp z, __LABEL3 + ld hl, _nfires + 4 + call __FP_PUSH_REV + ld a, 000h + ld de, 00000h + ld bc, 00000h + call __GTF + push af + ld hl, _fire + 4 + call __FP_PUSH_REV + ld a, 000h + ld de, 00000h + ld bc, 00000h + call __EQF + ld h, a + pop af + call __AND8 + or a + jp z, __LABEL5 + ld a, (_nsfx) + ld de, (_nsfx + 1) + ld bc, (_nsfx + 3) + call __FTOU32REG + push hl + ld a, 3 + pop hl + ld (hl), a + ld hl, _nfires + 4 + call __FP_PUSH_REV + ld a, 081h + ld de, 00000h + ld bc, 00000h + call __SUBF + ld hl, _nfires + call __STOREF + ld a, 1 + ld (_a), a + ld a, 081h + ld de, 00000h + ld bc, 00000h + ld hl, _keyspacepressed + call __STOREF +__LABEL5: +__LABEL3: + jp __LABEL1 +__LABEL0: + ld a, 000h + ld de, 00000h + ld bc, 00000h + ld hl, _keyspacepressed + call __STOREF +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "and8.asm" + + ; FASTCALL boolean and 8 version. + ; result in Accumulator (0 False, not 0 True) +; __FASTCALL__ version (operands: A, H) + ; Performs 8bit and 8bit and returns the boolean + +__AND8: + or a + ret z + ld a, h + ret + +#line 86 "ifcrash.bas" +#line 1 "eqf.asm" + +#line 1 "u32tofreg.asm" + +#line 1 "neg32.asm" + +__ABS32: + bit 7, d + ret z + +__NEG32: ; Negates DEHL (Two's complement) + ld a, l + cpl + ld l, a + + ld a, h + cpl + ld h, a + + ld a, e + cpl + ld e, a + + ld a, d + cpl + ld d, a + + inc l + ret nz + + inc h + ret nz + + inc de + ret + +#line 2 "u32tofreg.asm" +__I8TOFREG: + ld l, a + rlca + sbc a, a ; A = SGN(A) + ld h, a + ld e, a + ld d, a + +__I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) + ; to a Floating Point Number returned in (A ED CB) + + ld a, d + or a ; Test sign + + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __U32TOFREG ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + +__U8TOFREG: + ; Converts an unsigned 8 bit (A) to Floating point + ld l, a + ld h, 0 + ld e, h + ld d, h + +__U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in A ED CB + + PROC + + LOCAL __U32TOFREG_END + + ld a, d + or e + or h + or l + ld b, d + ld c, e ; Returns 00 0000 0000 if ZERO + ret z + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 128 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + +__U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG + exx + ld a, d ; B'C'D'E' == 0 ? + or e + or b + or c + jp z, __U32TOFREG_END ; We are done + + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry + rr c + rr d + rr e + exx + + rr e ; Shift EDCB >> 1, inserting the carry on the left + rr d + rr c + rr b + + inc l ; Increment exponent + jp __U32TOFREG_LOOP + + +__U32TOFREG_END: + exx + ld a, l ; Puts the exponent in a + res 7, e ; Sets the sign bit to 0 (positive) + + ret + ENDP + +#line 2 "eqf.asm" +#line 1 "ftou32reg.asm" + + + +__FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + ; Output: DEHL 32 bit number (signed) + PROC + + LOCAL __IS_FLOAT + + or a + jr nz, __IS_FLOAT + ; Here if it is a ZX ROM Integer + + ld h, c + ld l, d + ld a, e ; Takes sign: FF = -, 0 = + + ld de, 0 + inc a + jp z, __NEG32 ; Negates if negative + ret + +__IS_FLOAT: ; Jumps here if it is a true floating point number + ld h, e + push hl ; Stores it for later (Contains Sign in H) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + ;ld a, c ; Get exponent + sub 128 ; Exponent -= 128 + jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + +__FTOU32REG_LOOP: + exx ; Shift C'B' E'D' << 1, output bit stays in Carry + sla d + rl e + rl b + rl c + + exx ; Shift DEHL << 1, inserting the carry on the right + rl l + rl h + rl e + rl d + + djnz __FTOU32REG_LOOP + +__FTOU32REG_END: + pop af ; Take the sign bit + or a ; Sets SGN bit to 1 if negative + jp m, __NEG32 ; Negates DEHL + + ret + + ENDP + + +__FTOU8: ; Converts float in C ED LH to Unsigned byte in A + call __FTOU32REG + ld a, l + ret + +#line 3 "eqf.asm" +#line 1 "stackf.asm" + + ; ------------------------------------------------------------- + ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC + ; ------------------------------------------------------------- + + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) + __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) + +__FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) + ; Second argument to push into the stack calculator is popped out of the stack + ; Since the caller routine also receives the parameters into the top of the stack + ; four bytes must be removed from SP before pop them out + + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK + exx + pop hl ; Caller-Caller return addr + exx + pop hl ; Caller return addr + + pop af + pop de + pop bc + + push hl ; Caller return addr + exx + push hl ; Caller-Caller return addr + exx + + jp __FPSTACK_PUSH + + +__FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK + ; This format is specified in the ZX 48K Manual + ; You can push a 16 bit signed integer as + ; 0 SS LL HH 0, being SS the sign and LL HH the low + ; and High byte respectively + ld a, h + rla ; sign to Carry + sbc a, a ; 0 if positive, FF if negative + ld e, a + ld d, l + ld c, h + xor a + ld b, a + jp __FPSTACK_PUSH +#line 4 "eqf.asm" + + ; ------------------------------------------------------------- + ; Floating point library using the FP ROM Calculator (ZX 48K) + + ; All of them uses C EDHL registers as 1st paramter. + ; For binary operators, the 2n operator must be pushed into the + ; stack, in the order BC DE HL (B not used). + ; + ; Uses CALLEE convention + ; ------------------------------------------------------------- + + +__EQF: ; A = B + call __FPSTACK_PUSH2 + + ; ------------- ROM NOS-EQL + ld b, 0Eh ; For comparison operators, OP must be in B also + rst 28h + defb 0Eh + defb 38h; ; END CALC + + call __FPSTACK_POP + jp __FTOU8 ; Convert to 8 bits + +#line 87 "ifcrash.bas" + +#line 1 "gtf.asm" + + + + + + ; ------------------------------------------------------------- + ; Floating point library using the FP ROM Calculator (ZX 48K) + + ; All of them uses A EDCB registers as 1st paramter. + ; For binary operators, the 2n operator must be pushed into the + ; stack, in the order A DE BC. + ; + ; Uses CALLEE convention + ; ------------------------------------------------------------- + +__GTF: ; A > B + call __FPSTACK_PUSH2 ; ENTERS B, A + + ; ------------- ROM NOS-GRTR + ld b, 0Dh ; B < A + rst 28h + defb 0Dh ; B < A + defb 38h; ; END CALC + + call __FPSTACK_POP + jp __FTOU8; Convert to 8 bits + +#line 89 "ifcrash.bas" +#line 1 "pushf.asm" + + + ; Routine to push Float pointed by HL + ; Into the stack. Notice that the hl points to the last + ; byte of the FP number. + ; Uses H'L' B'C' and D'E' to preserve ABCDEHL registers + +__FP_PUSH_REV: + push hl + exx + pop hl + pop bc ; Return Address + ld d, (hl) + dec hl + ld e, (hl) + dec hl + push de + ld d, (hl) + dec hl + ld e, (hl) + dec hl + push de + ld d, (hl) + push de + push bc ; Return Address + exx + ret + + +#line 90 "ifcrash.bas" +#line 1 "storef.asm" + +__PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) + push de + ex de, hl ; DE <- HL + push ix + pop hl ; HL <- IX + add hl, de ; HL <- IX + HL + pop de + +__ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register + ex af, af' + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex af, af' + +__STOREF: ; Stores the given FP number in A EDCB at address HL + ld (hl), a + inc hl + ld (hl), e + inc hl + ld (hl), d + inc hl + ld (hl), c + inc hl + ld (hl), b + ret + +#line 91 "ifcrash.bas" +#line 1 "subf.asm" + + + + ; ------------------------------------------------------------- + ; Floating point library using the FP ROM Calculator (ZX 48K) + + ; All of them uses A EDCB registers as 1st paramter. + ; For binary operators, the 2n operator must be pushed into the + ; stack, in the order A DE BC. + ; + ; Uses CALLEE convention + ; ------------------------------------------------------------- + + +__SUBF: ; Subtraction + call __FPSTACK_PUSH2 ; ENTERS B, A + + ; ------------- ROM SUB + rst 28h + defb 01h ; EXCHANGE + defb 03h ; SUB + defb 38h; ; END CALC + + jp __FPSTACK_POP + +#line 92 "ifcrash.bas" + +ZXBASIC_USER_DATA: +_KEYSPACE: + DEFB 00, 00, 00, 00, 00 +_keyspacepressed: + DEFB 00, 00, 00, 00, 00 +_nfires: + DEFB 00, 00, 00, 00, 00 +_fire: + DEFB 00, 00, 00, 00, 00 +_nsfx: + DEFB 00, 00, 00, 00, 00 +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/ifcrash.bas b/tests/functional/ifcrash.bas new file mode 100755 index 000000000..778c65dab --- /dev/null +++ b/tests/functional/ifcrash.bas @@ -0,0 +1,12 @@ +IF KEYSPACE then + if keyspacepressed=0 then + if nfires>0 and fire=0 then + poke nsfx,3 + nfires=nfires-1 + a = 1 + keyspacepressed=1 + end if + end if +else + keyspacepressed=0 +end if diff --git a/zxblex.py b/zxblex.py index b948c537a..ac8235dfc 100755 --- a/zxblex.py +++ b/zxblex.py @@ -456,7 +456,7 @@ def t_preproc_ID(t): def t_preproc_NEWLINE(t): r'\r?\n' t.lexer.begin('INITIAL') - t.lexer.lineno += len(t.value) + t.lexer.lineno += 1 return t @@ -589,6 +589,7 @@ def t_INITIAL_bin_NEWLINE(t): global LABELS_ALLOWED t.lexer.lineno += 1 + t.value = '\n' LABELS_ALLOWED = True return t From 7c175fe62aebe1a5df859a454a73008298341a93 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 1 Dec 2017 20:17:58 +0100 Subject: [PATCH 138/247] add git attributes to avoid CR/LF conversion --- .gitattributes | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..fa1d1c12f --- /dev/null +++ b/.gitattributes @@ -0,0 +1,15 @@ + +* text=false + +*.bas -crlf +*.asm -crlf +*.bi -crlf + +*.txt text +*.md text +*.py text +*.ini text +*.yml text + +*.png binary + From f32c63fb7fa71c3eeec13cc5fcac58f629e63d2b Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 3 Dec 2017 20:17:08 +0100 Subject: [PATCH 139/247] bugfix: infinite loop while visiting nodes While the tree optimizer was traversing the AST, sometimes it entered infite loops due to cycles in the ADG (actually the AST is not a tree anymore). Fixed. Actually, upon further investigation, it seems it not "infinite loop time", but a "very very long time". To sum up, the optimizer was doing many repeated (and useles) tree traversal passed. Now they're dramatically reduced and so, the compiler has been speed up! Also add tests with a timeout to detect long compiling times. --- api/optimize.py | 44 +- tests/functional/optspeed.asm | 707 +++++++++++++++++++++++++++++++++ tests/functional/optspeed.bas | 163 ++++++++ tests/functional/test_basic.py | 1 + tox.ini | 1 + 5 files changed, 902 insertions(+), 14 deletions(-) create mode 100644 tests/functional/optspeed.asm create mode 100644 tests/functional/optspeed.bas diff --git a/api/optimize.py b/api/optimize.py index fee5e8476..69c818d2c 100644 --- a/api/optimize.py +++ b/api/optimize.py @@ -133,6 +133,14 @@ def visit_FUNCDECL(self, node): warning(node.entry.lineno, "Function '%s' is never called and has been ignored" % node.entry.name) yield self.NOP else: + node.children[1] = (yield ToVisit(node.entry)) + yield node + + def visit_FUNCTION(self, node): + if getattr(node, 'visited', False): + yield node + else: + node.visited = True yield (yield self.generic_visit(node)) def visit_LET(self, node): @@ -164,11 +172,11 @@ def visit_BLOCK(self, node): yield (yield self.generic_visit(node)) def visit_IF(self, node): - if self.O_LEVEL >= 1: - expr_ = (yield ToVisit(node.children[0])) - then_ = (yield ToVisit(node.children[1])) - else_ = (yield ToVisit(node.children[2])) if len(node.children) == 3 else self.NOP + expr_ = (yield ToVisit(node.children[0])) + then_ = (yield ToVisit(node.children[1])) + else_ = (yield ToVisit(node.children[2])) if len(node.children) == 3 else self.NOP + if self.O_LEVEL >= 1: if chk.is_null(then_, else_): api.errmsg.warning_empty_if(node.lineno) yield self.NOP @@ -187,22 +195,28 @@ def visit_IF(self, node): yield node return - yield (yield self.generic_visit(node)) + for i in range(len(node.children)): + node.children[i] = (expr_, then_, else_)[i] + yield node def visit_WHILE(self, node): + expr_ = (yield node.children[0]) + body_ = (yield node.children[1]) + if self.O_LEVEL >= 1: - expr_ = (yield node.children[0]) - body_ = (yield node.children[1]) if chk.is_number(expr_) and not expr_.value and not chk.is_block_accessed(body_): yield self.NOP return - yield (yield self.generic_visit(node)) + + for i, child in enumerate((expr_, body_)): + node.children[i] = child + yield node def visit_FOR(self, node): - from_ = node.children[1] - to_ = node.children[2] - step_ = node.children[3] - body_ = node.children[4] + from_ = (yield node.children[1]) + to_ = (yield node.children[2]) + step_ = (yield node.children[3]) + body_ = (yield node.children[4]) if self.O_LEVEL > 0 and chk.is_number(from_, to_, step_) and not chk.is_block_accessed(body_): if from_ > to_ and step_ > 0: @@ -211,7 +225,10 @@ def visit_FOR(self, node): if from_ < to_ and step_ < 0: yield self.NOP return - yield (yield self.generic_visit(node)) + + for i, child in enumerate((from_, to_, step_, body_), start=1): + node.children[i] = child + yield node # TODO: ignore unused labels def _visit_LABEL(self, node): @@ -224,5 +241,4 @@ def _visit_LABEL(self, node): def generic_visit(node): for i in range(len(node.children)): node.children[i] = (yield ToVisit(node.children[i])) - yield node diff --git a/tests/functional/optspeed.asm b/tests/functional/optspeed.asm new file mode 100644 index 000000000..f79e8b17d --- /dev/null +++ b/tests/functional/optspeed.asm @@ -0,0 +1,707 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei +__LABEL__finish: + call _choque + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +_choque: + push ix + ld ix, 0 + add ix, sp + ld hl, 0 + push hl + push hl + push hl + call _choque + dec a + jp nz, __LABEL0 + ld a, (_face) + or a + jp nz, __LABEL3 + xor a + ld hl, (_ds1 - 1) + sub h + ccf + jp nc, __LABEL4 + ld a, 1 + ld (_face), a + ld (ix-1), 3 + jp __LABEL5 +__LABEL4: + ld a, 3 + ld (_face), a + ld (ix-1), 4 +__LABEL5: +__LABEL3: + jp __LABEL1 +__LABEL0: + call _choque + sub 8 + jp nz, __LABEL6 + ld a, (_face) + sub 3 + jp nz, __LABEL9 + push ix + pop hl + ld de, -6 + add hl, de + call __PLOADF + push bc + push de + push af + ld a, 000h + ld de, 00000h + ld bc, 00000h + call __LEF + or a + jp z, __LABEL10 + ld a, 2 + ld (_face), a + ld (ix-1), 4 + jp __LABEL11 +__LABEL10: + xor a + ld (_face), a + ld (ix-1), 3 +__LABEL11: +__LABEL9: + jp __LABEL7 +__LABEL6: + call _choque + sub 3 + jp nz, __LABEL12 + ld a, (_face) + or a + jp nz, __LABEL14 + ld a, 3 + ld (_face), a + ld (ix-1), 4 + jp __LABEL15 +__LABEL14: + ld a, (_face) + dec a + jp nz, __LABEL17 + ld a, 2 + ld (_face), a + ld (ix-1), 3 +__LABEL17: +__LABEL15: + jp __LABEL13 +__LABEL12: + call _choque + sub 6 + jp nz, __LABEL18 + ld a, (_face) + dec a + jp nz, __LABEL20 + xor a + ld (_face), a + ld (ix-1), 4 + jp __LABEL21 +__LABEL20: + ld a, (_face) + sub 2 + jp nz, __LABEL23 + ld a, 3 + ld (_face), a + ld (ix-1), 3 +__LABEL23: +__LABEL21: + jp __LABEL19 +__LABEL18: + call _choque + sub 12 + jp nz, __LABEL24 + ld a, (_face) + sub 2 + jp nz, __LABEL26 + ld a, 1 + ld (_face), a + ld (ix-1), 4 + jp __LABEL27 +__LABEL26: + ld a, (_face) + sub 3 + jp nz, __LABEL29 + xor a + ld (_face), a + ld (ix-1), 3 +__LABEL29: +__LABEL27: + jp __LABEL25 +__LABEL24: + call _choque + sub 9 + jp nz, __LABEL30 + ld a, (_face) + or a + jp nz, __LABEL32 + ld a, 1 + ld (_face), a + ld (ix-1), 3 + jp __LABEL33 +__LABEL32: + ld a, (_face) + sub 3 + jp nz, __LABEL35 + ld a, 2 + ld (_face), a + ld (ix-1), 4 +__LABEL35: +__LABEL33: + jp __LABEL31 +__LABEL30: + call _choque + sub 7 + jp nz, __LABEL36 + ld a, (_face) + sub 3 + jp z, __LABEL__finish +__LABEL39: + ld a, (_face) + sub 2 + jp nz, __LABEL40 + ld (ix-1), 3 + jp __LABEL41 +__LABEL40: + ld (ix-1), 4 +__LABEL41: + ld a, 3 + ld (_face), a + jp __LABEL37 +__LABEL36: + call _choque + sub 14 + jp nz, __LABEL42 + ld a, (_face) + or a + jp z, __LABEL__finish +__LABEL45: + ld a, (_face) + sub 3 + jp nz, __LABEL46 + ld (ix-1), 3 + jp __LABEL47 +__LABEL46: + ld (ix-1), 4 +__LABEL47: + xor a + ld (_face), a + jp __LABEL43 +__LABEL42: + call _choque + sub 13 + jp nz, __LABEL48 + ld a, (_face) + dec a + jp z, __LABEL__finish +__LABEL51: + ld a, (_face) + sub 2 + jp nz, __LABEL52 + ld (ix-1), 3 + jp __LABEL53 +__LABEL52: + ld (ix-1), 4 +__LABEL53: + ld a, 1 + ld (_face), a + jp __LABEL49 +__LABEL48: + call _choque + sub 11 + jp nz, __LABEL54 + ld a, (_face) + sub 2 + jp z, __LABEL__finish +__LABEL57: + ld a, (_face) + sub 3 + jp nz, __LABEL58 + ld (ix-1), 4 + jp __LABEL59 +__LABEL58: + ld (ix-1), 3 +__LABEL59: + ld a, 2 + ld (_face), a + jp __LABEL55 +__LABEL54: + call _choque + sub 5 + jp nz, __LABEL60 + ld a, (_face) + or a + jp nz, __LABEL62 + xor a + ld hl, (_ds1 - 1) + sub h + ccf + jp nc, __LABEL64 + ld a, 1 + ld (_face), a + ld (ix-1), 3 + jp __LABEL65 +__LABEL64: + ld a, 3 + ld (_face), a + ld (ix-1), 4 +__LABEL65: + jp __LABEL63 +__LABEL62: + ld a, (_face) + sub 2 + jp nz, __LABEL67 + xor a + ld hl, (_ds1 - 1) + sub h + ccf + jp nc, __LABEL68 + ld a, 1 + ld (_face), a + ld (ix-1), 4 + jp __LABEL69 +__LABEL68: + ld a, 3 + ld (_face), a + ld (ix-1), 3 +__LABEL69: +__LABEL67: +__LABEL63: + jp __LABEL61 +__LABEL60: + call _choque + sub 10 + jp nz, __LABEL71 + ld a, (_face) + dec a + jp nz, __LABEL72 + push ix + pop hl + ld de, -6 + add hl, de + call __PLOADF + push bc + push de + push af + ld a, 000h + ld de, 00000h + ld bc, 00000h + call __LEF + or a + jp z, __LABEL74 + ld a, 2 + ld (_face), a + ld (ix-1), 3 + jp __LABEL75 +__LABEL74: + xor a + ld (_face), a + ld (ix-1), 4 +__LABEL75: + jp __LABEL73 +__LABEL72: + ld a, (_face) + sub 3 + jp nz, __LABEL77 + push ix + pop hl + ld de, -6 + add hl, de + call __PLOADF + push bc + push de + push af + ld a, 000h + ld de, 00000h + ld bc, 00000h + call __LEF + or a + jp z, __LABEL78 + ld a, 2 + ld (_face), a + ld (ix-1), 4 + jp __LABEL79 +__LABEL78: + xor a + ld (_face), a + ld (ix-1), 3 +__LABEL79: +__LABEL77: +__LABEL73: +__LABEL71: +__LABEL61: +__LABEL55: +__LABEL49: +__LABEL43: +__LABEL37: +__LABEL31: +__LABEL25: +__LABEL19: +__LABEL13: +__LABEL7: +__LABEL1: +_choque__leave: + ld sp, ix + pop ix + ret +#line 1 "lef.asm" + +#line 1 "u32tofreg.asm" + +#line 1 "neg32.asm" + +__ABS32: + bit 7, d + ret z + +__NEG32: ; Negates DEHL (Two's complement) + ld a, l + cpl + ld l, a + + ld a, h + cpl + ld h, a + + ld a, e + cpl + ld e, a + + ld a, d + cpl + ld d, a + + inc l + ret nz + + inc h + ret nz + + inc de + ret + +#line 2 "u32tofreg.asm" +__I8TOFREG: + ld l, a + rlca + sbc a, a ; A = SGN(A) + ld h, a + ld e, a + ld d, a + +__I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) + ; to a Floating Point Number returned in (A ED CB) + + ld a, d + or a ; Test sign + + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __U32TOFREG ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + +__U8TOFREG: + ; Converts an unsigned 8 bit (A) to Floating point + ld l, a + ld h, 0 + ld e, h + ld d, h + +__U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in A ED CB + + PROC + + LOCAL __U32TOFREG_END + + ld a, d + or e + or h + or l + ld b, d + ld c, e ; Returns 00 0000 0000 if ZERO + ret z + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 128 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + +__U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG + exx + ld a, d ; B'C'D'E' == 0 ? + or e + or b + or c + jp z, __U32TOFREG_END ; We are done + + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry + rr c + rr d + rr e + exx + + rr e ; Shift EDCB >> 1, inserting the carry on the left + rr d + rr c + rr b + + inc l ; Increment exponent + jp __U32TOFREG_LOOP + + +__U32TOFREG_END: + exx + ld a, l ; Puts the exponent in a + res 7, e ; Sets the sign bit to 0 (positive) + + ret + ENDP + +#line 2 "lef.asm" +#line 1 "ftou32reg.asm" + + + +__FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + ; Output: DEHL 32 bit number (signed) + PROC + + LOCAL __IS_FLOAT + + or a + jr nz, __IS_FLOAT + ; Here if it is a ZX ROM Integer + + ld h, c + ld l, d + ld a, e ; Takes sign: FF = -, 0 = + + ld de, 0 + inc a + jp z, __NEG32 ; Negates if negative + ret + +__IS_FLOAT: ; Jumps here if it is a true floating point number + ld h, e + push hl ; Stores it for later (Contains Sign in H) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + ;ld a, c ; Get exponent + sub 128 ; Exponent -= 128 + jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + +__FTOU32REG_LOOP: + exx ; Shift C'B' E'D' << 1, output bit stays in Carry + sla d + rl e + rl b + rl c + + exx ; Shift DEHL << 1, inserting the carry on the right + rl l + rl h + rl e + rl d + + djnz __FTOU32REG_LOOP + +__FTOU32REG_END: + pop af ; Take the sign bit + or a ; Sets SGN bit to 1 if negative + jp m, __NEG32 ; Negates DEHL + + ret + + ENDP + + +__FTOU8: ; Converts float in C ED LH to Unsigned byte in A + call __FTOU32REG + ld a, l + ret + +#line 3 "lef.asm" +#line 1 "stackf.asm" + + ; ------------------------------------------------------------- + ; Functions to manage FP-Stack of the ZX Spectrum ROM CALC + ; ------------------------------------------------------------- + + + __FPSTACK_PUSH EQU 2AB6h ; Stores an FP number into the ROM FP stack (A, ED CB) + __FPSTACK_POP EQU 2BF1h ; Pops an FP number out of the ROM FP stack (A, ED CB) + +__FPSTACK_PUSH2: ; Pushes Current A ED CB registers and top of the stack on (SP + 4) + ; Second argument to push into the stack calculator is popped out of the stack + ; Since the caller routine also receives the parameters into the top of the stack + ; four bytes must be removed from SP before pop them out + + call __FPSTACK_PUSH ; Pushes A ED CB into the FP-STACK + exx + pop hl ; Caller-Caller return addr + exx + pop hl ; Caller return addr + + pop af + pop de + pop bc + + push hl ; Caller return addr + exx + push hl ; Caller-Caller return addr + exx + + jp __FPSTACK_PUSH + + +__FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK + ; This format is specified in the ZX 48K Manual + ; You can push a 16 bit signed integer as + ; 0 SS LL HH 0, being SS the sign and LL HH the low + ; and High byte respectively + ld a, h + rla ; sign to Carry + sbc a, a ; 0 if positive, FF if negative + ld e, a + ld d, l + ld c, h + xor a + ld b, a + jp __FPSTACK_PUSH +#line 4 "lef.asm" + + ; ------------------------------------------------------------- + ; Floating point library using the FP ROM Calculator (ZX 48K) + + ; All of them uses A EDCB registers as 1st paramter. + ; For binary operators, the 2n operator must be pushed into the + ; stack, in the order A DE BC. + ; + ; Uses CALLEE convention + ; ------------------------------------------------------------- + +__LEF: ; A <= B + call __FPSTACK_PUSH2 ; B, A + + ; ------------- ROM NO-L-EQL + ld b, 0Ah ; B => A + rst 28h + defb 0Ah ; B => A + defb 38h; ; END CALC + + call __FPSTACK_POP + jp __FTOU8 ; Convert to 8 bits + +#line 361 "optspeed.bas" +#line 1 "ploadf.asm" + + ; Parameter / Local var load + ; A => Offset + ; IX = Stack Frame +; RESULT: HL => IX + DE + +#line 1 "iloadf.asm" + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- ((HL)) + +__ILOADF: + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- (HL) + +__LOADF: ; Loads a 40 bits FP number from address pointed by HL + ld a, (hl) + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld c, (hl) + inc hl + ld b, (hl) + ret + +#line 7 "ploadf.asm" + +__PLOADF: + push ix + pop hl + add hl, de + jp __LOADF + +#line 362 "optspeed.bas" + +ZXBASIC_USER_DATA: +_face: + DEFB 00 +_modoi: + DEFB 00 +_ds1: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/optspeed.bas b/tests/functional/optspeed.bas new file mode 100644 index 000000000..9f9e00a8a --- /dev/null +++ b/tests/functional/optspeed.bas @@ -0,0 +1,163 @@ +DIM face, modoi, ds1 as Ubyte + +function choque() as UByte + if choque=1 + if face=0 then + if ds1<=0 then + face=1 ' FACE + modo=3 ' GIRA IZDA + else + face=3 + modo=4 ' GIRA DCHA + end if + end if + + elseif choque=8 + if face=3 then + if ds2<=0 then + face=2 + modo=4 + else + face=0 + modo=3 + end if + end if + + elseif choque=3 + if face=0 then + face=3 + modo=4 + 'end if + + elseif face=1 then + face=2 + modo=3 + end if + + elseif choque=6 + if face=1 then + face=0 + modo=4 + 'end if + + elseif face=2 then + face=3 + modo=3 + end if + + elseif choque=12 + if face=2 then + face=1 + modo=4 + 'end if + + elseif face=3 then + face=0 + modo=3 + end if + + elseif choque=9 + if face=0 then + face=1 + modo=3 + 'end if + + elseif face=3 then + face=2 + modo=4 + end if + + elseif choque=7 + if face=3 then + goto finish + end if + + if face=2 then + modo=3 + else + modo=4 + end if + face=3 + + elseif choque=14 + if face=0 then + goto finish + end if + + if face=3 then + modo=3 + else + modo=4 + end if + face=0 + + elseif choque=13 + if face=1 then + goto finish + end if + + if face=2 then + modo=3 + else + modo=4 + end if + + face=1 + + elseif choque=11 + if face=2 then + goto finish + end if + + if face=3 then + modo=4 + else + modo=3 + end if + + face=2 + + elseif choque=5 + + if face=0 then + if ds1<=0 then + face=1 + modo=3 + else + face=3 + modo=4 + end if + elseif face=2 then + if ds1<=0 then + face=1 + modo=4 + else + face=3 + modo=3 + end if + end if + + elseif choque=10 + + if face=1 then + if ds2<=0 then + face=2 + modo=3 + else + face=0 + modo=4 + end if + elseif face=3 then + if ds2<=0 then + face=2 + modo=4 + else + face=0 + modo=3 + end if + end if + end if +end function +finish: +choque + diff --git a/tests/functional/test_basic.py b/tests/functional/test_basic.py index c387230c6..9318f89c2 100755 --- a/tests/functional/test_basic.py +++ b/tests/functional/test_basic.py @@ -11,6 +11,7 @@ @pytest.mark.parametrize('fname', [os.path.join(TEST_PATH, f) for f in os.listdir(TEST_PATH) if f.endswith(".bas")]) +@pytest.mark.timeout(5) def test_basic(fname): test.main(['-d', '-e', '/dev/null', fname]) if test.COUNTER == 0: diff --git a/tox.ini b/tox.ini index 680ec0852..4e1fffb00 100644 --- a/tox.ini +++ b/tox.ini @@ -6,6 +6,7 @@ setenv = LANG=en_US.UTF-8 deps = pytest pytest-cov + pytest-timeout -rrequirements.txt commands = py.test \ From 33ed90b9864377984640497258af40e66afc7057 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 10 Dec 2017 23:19:26 +0100 Subject: [PATCH 140/247] bugfix: fixes a bug in the -O3 optimizer which now produces even better code. --- arch/zx48k/optimizer.py | 346 +++++++++++++---------------- tests/functional/opt3_atoloinc.asm | 5 +- tests/functional/opt3_haplobug.asm | 67 ++++++ tests/functional/opt3_haplobug.bas | 13 ++ tests/functional/opt3_lcd5.asm | 10 +- 5 files changed, 237 insertions(+), 204 deletions(-) create mode 100644 tests/functional/opt3_haplobug.asm create mode 100644 tests/functional/opt3_haplobug.bas diff --git a/arch/zx48k/optimizer.py b/arch/zx48k/optimizer.py index e7c44214d..9fbb0df9f 100644 --- a/arch/zx48k/optimizer.py +++ b/arch/zx48k/optimizer.py @@ -18,6 +18,7 @@ import arch.zx48k.backend from collections import defaultdict +UNKNOWN_PREFIX = '*UNKNOWN_' END_PROGRAM_LABEL = '__END_PROGRAM' # Label for end program sys.setrecursionlimit(10000) @@ -88,7 +89,7 @@ def new_tmp_val(): global RAND_COUNT RAND_COUNT += 1 - return '*UNKNOWN_{0}'.format(RAND_COUNT) + return '{0}{1}'.format(UNKNOWN_PREFIX, RAND_COUNT) def is_8bit_normal_register(x): @@ -144,12 +145,15 @@ def is_number(x): if x is None: return False - if isinstance(x, int) or isinstance(x, float): + if isinstance(x, (int, float)): return True + if isinstance(x, str) and x[0] == '(' and x[-1] == ')': + return False + try: tmp = eval(x, {}, {}) - if isinstance(tmp, int) or isinstance(tmp, float): + if isinstance(tmp, (int, float)): return True except: pass @@ -157,6 +161,10 @@ def is_number(x): return RE_NUMBER.match(str(x)) is not None +def is_unknown(x): + return x is None or x.startswith(UNKNOWN_PREFIX) + + def valnum(x): if not is_number(x): return None @@ -359,177 +367,141 @@ def reset(self): """ self.regs = {} self.stack = [] - self.mem_regs = defaultdict(set) # list of labels and registers using then - self.mem = {} # List of labels and their values + self.mem = defaultdict(new_tmp_val) # Dict of label -> value in memory for i in 'abcdefhl': - self.regs[i] = None # Initial unknown state - self.regs["%s'" % i] = None - - self.regs['ixh'] = None - self.regs['ixl'] = None - self.regs['iyh'] = None - self.regs['iyl'] = None - self.regs['sp'] = None - self.regs['r'] = None - self.regs['i'] = None - - self.regs['af'] = None - self.regs['bc'] = None - self.regs['de'] = None - self.regs['hl'] = None - - self.regs['ix'] = None - self.regs['iy'] = None - - self.regs["af'"] = None - self.regs["bc'"] = None - self.regs["de'"] = None - self.regs["hl'"] = None + self.regs[i] = new_tmp_val() # Initial unknown state + self.regs["%s'" % i] = new_tmp_val() + + self.regs['ixh'] = new_tmp_val() + self.regs['ixl'] = new_tmp_val() + self.regs['iyh'] = new_tmp_val() + self.regs['iyl'] = new_tmp_val() + self.regs['sp'] = new_tmp_val() + self.regs['r'] = new_tmp_val() + self.regs['i'] = new_tmp_val() + + self.regs['af'] = new_tmp_val() + self.regs['bc'] = new_tmp_val() + self.regs['de'] = new_tmp_val() + self.regs['hl'] = new_tmp_val() + + self.regs['ix'] = new_tmp_val() + self.regs['iy'] = new_tmp_val() + + self.regs["af'"] = new_tmp_val() + self.regs["bc'"] = new_tmp_val() + self.regs["de'"] = new_tmp_val() + self.regs["hl'"] = new_tmp_val() self._16bit = {'b': 'bc', 'c': 'bc', 'd': 'de', 'e': 'de', 'h': 'hl', 'l': 'hl', "b'": "bc'", "c'": "bc'", "d'": "de'", "e'": "de'", "h'": "hl'", "l'": "hl'", 'ixy': 'ix', 'ixl': 'ix', 'iyh': 'iy', 'iyl': 'iy', 'a': 'af', "a'": "af'", 'f': 'af', "f'": "af'"} - self.C = self.Z = self.P = self.S = None + self.reset_flags() + + def reset_flags(self): + """ Resets flags to an "unknown state" + """ + self.C = None + self.Z = None + self.P = None + self.S = None def set(self, r, val): - is_num = is_number(val) - if is_num: + if val is None: + is_num = False + val = new_tmp_val() + else: val = str(val) - - if is_num and self.getv(r) == valnum(val) & 0xFFFF: - return # The register already contains it value + is_num = is_number(val) + if is_num and self.getv(r) == valnum(val) & 0xFFFF: + return # The register already contains this value if r == '(sp)': if not self.stack: - self.stack = [None] + self.stack = [new_tmp_val()] self.stack[-1] = str(valnum(val) & 0xFFFF) if is_num else val return - if r[0] == '(': + if r[0] == '(': # (mem) <- r => store in memory address r = r[1:-1].strip() if not RE_ID.match(r): return # not an ID if r in self.mem and val == self.mem[r]: - return # the same value to the same pos does nothing... (strong assumption) - # Ok, destroys cached value of any register containing this variable if any - for r_ in self.mem_regs[r]: - self.regs[r_] = None - if r_ == 'f': - self.C = self.Z = self.P = self.S = None - old_set = self.mem_regs[r] - self.mem_regs[r] = set() - self.mem[r] = self.regs.get(val, None) - for r_ in old_set: - if r_ in self.mem_regs: - self.set('(%s)' % r_, None) - if val in self.regs and self.regs[val] is None: # is a register? - self.set(val, '(%s)' % r) # mark it again, because now register contains (label) value + return # the same value to the same pos does nothing... (strong assumption: NON-VOLATILE) + if val not in self.regs: + self.regs[val] = new_tmp_val() + self.mem[r] = self.regs[val] return - if val and val[0] == '(': - if RE_ID.match(val[1:-1]): - v_ = val[1:-1] + if val and val[0] == '(': # r <- (mem) + v_ = val[1:-1].strip() + if RE_ID.match(v_): if v_ in self.mem: - self.set(r, self.mem[v_]) - r_ = self._16bit[r] if is_8bit_register(r) else r - self.mem_regs[v_].add(r_) - self.mem_regs[v_].update(single_registers(r_)) + val = self.mem[v_] + else: + val = self.mem[v_] = new_tmp_val() else: - self.set(r, None) - return + val = new_tmp_val() if is_8bit_register(r): if is_register(val): - self.regs[r] = self.regs[val] - val = self.regs[val] + val = self.regs[r] = self.regs[val] else: if is_num: oldval = self.getv(r) val = str(valnum(val) & 0xFF) if val == oldval: # Does not change return - self.regs[r] = val - # This change will reset any value related to this register - for reg8 in list('abcdehl') + ['ixh', 'ixl', 'iyh', 'iyl', - "a'", "b'", "c'", "d'", "e'", "h'", "l'"]: - tmp = self.regs[reg8] - if tmp is None or is_number(tmp): - continue - - if tmp[0] == '(': # (de), (hl), (ix+...), ( - tmp = tmp[1:-1] - - if r in tmp: # if other register depended on this - self.set(reg8, None) # the cached info is deleted - - if r not in self._16bit.keys(): + if r not in self._16bit: return hl = self._16bit[r] + self.mem[hl] = new_tmp_val() # Changing a 16 bit regs means changing the content of its *memptr + if not is_num or not is_number(self.regs[hl]): - self.regs[hl] = None # unknown + self.regs[hl] = new_tmp_val() # unknown return val = int(val) if r in {'b', 'd', 'h', 'ixh', 'iyh', "b'", "d'", "h'"}: # high register self.regs[hl] = str((val << 8) + int(self.regs[LO16(hl)])) - return + else: + self.regs[hl] = str((self.regs[HI16(hl)] << 8) + val) - self.regs[hl] = str((self.regs[HI16(hl)] << 8) + val) return # a 16 bit reg self.regs[r] = val - if is_16bit_register(r): # sp register is not included. Special case + self.mem[r] = new_tmp_val() + if not is_num: - self.regs[LO16(r)] = self.regs[HI16(r)] = None + self.regs[LO16(r)] = new_tmp_val() + self.regs[HI16(r)] = new_tmp_val() else: val = valnum(val) - self.regs[LO16(r)] = val & 0xFF - self.regs[HI16(r)] = val >> 8 - - # This change will reset any value related to this register - for reg16 in {'bc', 'de', 'hl', "bc'", "de'", "hl'", 'ix', 'iy'}: - tmp = self.regs[reg16] - if tmp is None or is_number(tmp): - continue + self.regs[LO16(r)] = str(val & 0xFF) + self.regs[HI16(r)] = str(val >> 8) - if self.regs[reg16] == r: # any register - self.regs[reg16] = None - self.set(LO16(reg16), None) # Recursively destroys any register - self.set(HI16(reg16), None) # Depending on this one - - for reg8 in list('abcdehl') + ['ixh', 'ixl', 'iyh', 'iyl', - "a'", "b'", "c'", "d'", "e'", "h'", "l'"]: - tmp = self.regs[reg8] - if tmp is None or is_number(tmp): - continue - - if tmp[0] == '(': # (de), (hl), (ix+...), ( - tmp = tmp[0:2] - - if r[0] in tmp or r[1] in tmp: # if other register depended on this - self.set(reg8, None) # the cached info is deleted - # Flags ??? - # self.C = self.S = self.Z = self.P = None + if 'f' in r: + self.reset_flags() def get(self, r): """ Returns precomputed value of the given expression """ - if r[:1] == '(' and r[-1:] == ')' and r[1:-1] in self.mem: + if r.lower() == '(sp)' and self.stack: + return self.stack[-1] + + if r[:1] == '(': return self.mem[r[1:-1]] r = r.lower() - if r == '(sp)' and len(self.stack): - return self.stack[-1] - if is_number(r): return str(valnum(r)) @@ -542,12 +514,13 @@ def getv(self, r): """ Like the above, but returns the value. """ v = self.get(r) - if v is not None: + if not is_unknown(v): try: v = int(v) - except: + except ValueError: v = None - + else: + v = None return v def eq(self, r1, r2): @@ -563,7 +536,8 @@ def eq(self, r1, r2): def set_flag(self, val): if not is_number(val): - self.regs['f'] = self.C = self.S = self.Z = self.P = None + self.regs['f'] = new_tmp_val() + self.reset_flags() return self.set('f', val) @@ -576,104 +550,114 @@ def set_flag(self, val): def inc(self, r): """ Does inc on the register and precomputes flags """ - if not is_register(r): - self.set_flag(None) + self.set_flag(None) - if r[0] == '(': - for i in self.regs.keys(): - if self.regs[i] == r: - self.set(i, None) + if not is_register(r): + if r[0] == '(': # a memory position, basically: inc(hl) + r_ = r[1:-1].strip() + v_ = self.getv(self.mem.get(r_, None)) + if v_ is not None: + v_ = (v_ + 1) & 0xFF + self.mem[r_] = str(v_) + self.Z = int(v_ == 0) # HINT: This might be improved + else: + self.mem[r_] = new_tmp_val() return if self.getv(r) is not None: self.set(r, self.getv(r) + 1) - return - - self.set(r, None) + else: + self.set(r, None) def dec(self, r): """ Does dec on the register and precomputes flags """ - if not is_register(r): - self.set_flag(None) + self.set_flag(None) - if r[0] == '(': - for i in self.regs.keys(): - if self.regs[i] == r: - self.set(i, None) + if not is_register(r): + if r[0] == '(': # a memory position, basically: inc(hl) + r_ = r[1:-1].strip() + v_ = self.getv(self.mem.get(r_, None)) + if v_ is not None: + v_ = (v_ - 1) & 0xFF + self.mem[r_] = str(v_) + self.Z = int(v_ == 0) # HINT: This might be improved + else: + self.mem[r_] = new_tmp_val() return if self.getv(r) is not None: self.set(r, self.getv(r) - 1) - return - - self.set(r, None) + else: + self.set(r, None) def rrc(self, r): """ Does a ROTATION to the RIGHT |>> """ - if self.regs[r] is None or isinstance(self.regs[r], str): + if not is_number(self.regs[r]): self.set(r, None) self.set_flag(None) return - self.regs[r] = (self.regs[r] >> 1) | ((self.regs[r] & 1) << 7) + v_ = self.getv(self.regs[r]) & 0xFF + self.regs[r] = str((v_ >> 1) | ((v_ & 1) << 7)) def rr(self, r): """ Like the above, bus uses carry """ - if self.C is None or self.regs[r] is None or isinstance(self.regs[r], str): + if self.C is None or not is_number(self.regs[r]): self.set(r, None) self.set_flag(None) return self.rrc(r) tmp = self.C - self.C = self.regs[r] >> 7 - self.regs[r] = (self.regs[r] & 0x7F) | (tmp << 7) + v_ = self.getv(self.regs[r]) + self.C = v_ >> 7 + self.regs[r] = str((v_ & 0x7F) | (tmp << 7)) def rlc(self, r): """ Does a ROTATION to the LEFT <<| """ - if self.regs[r] is None or isinstance(self.regs[r], str): + if not is_number(self.regs[r]): self.set(r, None) self.set_flag(None) return - self.set(r, ((self.regs[r] << 1) & 0xFF) | ((self.regs[r] & 1) >> 7)) + v_ = self.getv(self.regs[r]) & 0xFF + self.set(r, ((v_ << 1) & 0xFF) | (v_ >> 7)) def rl(self, r): """ Like the above, bus uses carry """ - if self.C is None or self.regs[r] is None or isinstance(self.regs[r], str): + if self.C is None or not is_number(self.regs[r]): self.set(r, None) self.set_flag(None) return self.rlc(r) tmp = self.C - self.C = self.regs[r] & 1 - self.regs[r] = (self.regs[r] & 0xFE) | tmp + v_ = self.getv(self.regs[r]) + self.C = v_ & 1 + self.regs[r] = str((v_ & 0xFE) | tmp) def _is(self, r, val): """ True if value of r is val. """ - if not is_register(r): + if not is_register(r) or val is None: return False r = r.lower() - - if self.regs[r] is None: - return False - if is_register(val): - if self.regs[val] is None: - return False - - return self.regs[val] == self.regs[r] + return self.eq(r, val) if is_number(val): val = str(valnum(val)) + else: + val = str(val) + + if val[0] == '(': + val = self.mem[val[1:-1]] return self.regs[r] == val @@ -690,55 +674,27 @@ def op(self, i, o): return if i == 'push': - if self.regs['sp'] is not None: - if RE_IXIND.match(self.regs['sp']): - tmp = self.regs['sp'].lower() - - if tmp in ('ix', 'iy'): - tmp += '-2' - else: - tmp = tmp[:2] + "%+i" % (int(tmp[2:]) - 2) - - self.set('sp', tmp) - elif valnum(self.regs['sp']): - self.set('sp', self.regs['sp'] - 2) - else: - self.set('sp', None) - - self.stack += [self.regs[o[0]]] + if valnum(self.regs['sp']): + self.set('sp', (self.getv(self.regs['sp']) - 2) % 0xFFFF) + else: + self.set('sp', None) + self.stack.append(self.regs[o[0]]) return if i == 'pop': - if self.stack == []: - self.set(o[0], None) - return - - self.set(o[0], self.stack[-1]) - self.stack.pop() - return - - if i in ('inc', 'dec'): - r = o[0] - - if i == 'inc': - self.inc(r) + self.set(o[0], self.stack and self.stack.pop() or None) + if valnum(self.regs['sp']): + self.set('sp', (self.getv(self.regs['sp']) + 2) % 0xFFFF) else: - self.dec(r) - - if is_16bit_register(r): - for i, v in zip(self.regs.keys(), self.regs.values()): - if v == r: # Value == '(hl)' or (SP), (IX) ... - self.set(i, None) - # Since hl has changed, every (hl) instance must be deleted here. - - # inc/dec on 16bit regs does not affect flags - return + self.set('sp', None) + return - if self.getv(r) is None: - self.set_flag(None) - return + if i == 'inc': + self.inc(o[0]) + return - self.Z = int(self.getv(r)) == 0 + if i == 'dec': + self.dec(o[0]) return if i == 'rra': diff --git a/tests/functional/opt3_atoloinc.asm b/tests/functional/opt3_atoloinc.asm index c4d35207c..f173e4acc 100644 --- a/tests/functional/opt3_atoloinc.asm +++ b/tests/functional/opt3_atoloinc.asm @@ -23,9 +23,8 @@ __START_PROGRAM: ld (_doorstate), a ld a, (_doorid) ld (_doorstate), a - ld hl, _nfires - inc (hl) - ld a, (_key) + inc a + ld (_nfires), a ld (_level), a ld a, (_doorstate) ld (_nfires), a diff --git a/tests/functional/opt3_haplobug.asm b/tests/functional/opt3_haplobug.asm new file mode 100644 index 000000000..306e25366 --- /dev/null +++ b/tests/functional/opt3_haplobug.asm @@ -0,0 +1,67 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, (_dataSprite) + ld de, 26 + add hl, de + ld de, 0 + ld (hl), e + inc hl + ld (hl), d + ld hl, (_dataSprite) + ld de, 11 + add hl, de + push hl + ld hl, (_dataSprite) + ld de, 28 + add hl, de + ld a, (hl) + pop hl + ld (hl), a + ld hl, (_dataSprite) + ld de, 12 + add hl, de + push hl + ld hl, (_dataSprite) + ld de, 29 + add hl, de + ld a, (hl) + pop hl + ld (hl), a + ld hl, (_dataSprite) + ld de, 30 + add hl, de + xor a + ld (hl), a + ld bc, 0 +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + pop iy + pop ix + exx + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_dataSprite: + DEFB 00, 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/opt3_haplobug.bas b/tests/functional/opt3_haplobug.bas new file mode 100644 index 000000000..3cc394018 --- /dev/null +++ b/tests/functional/opt3_haplobug.bas @@ -0,0 +1,13 @@ +#define spriteX (dataSprite+11) +#define spriteY (dataSprite+12) +#define spriteOldX (dataSprite+28) +#define spriteOldY (dataSprite+29) +#define spriteEsp0 (dataSprite+30) +#define spriteTimer (dataSprite+26) + +DIM dataSprite as Uinteger +poke UInteger spriteTimer,0 +poke spriteX, peek (spriteOldX) +poke spriteY, peek (spriteOldY) +poke spriteEsp0,0 + diff --git a/tests/functional/opt3_lcd5.asm b/tests/functional/opt3_lcd5.asm index 26c366052..a43a21965 100644 --- a/tests/functional/opt3_lcd5.asm +++ b/tests/functional/opt3_lcd5.asm @@ -176,12 +176,10 @@ _ScanNear: ld a, (ix+7) dec a ld l, a - ld h, 0 push hl ld a, (ix+5) dec a ld l, a - ld h, 0 push hl call _ScanField dec a @@ -384,7 +382,7 @@ __AND8: ld a, h ret -#line 363 "opt3_lcd5.bas" +#line 361 "opt3_lcd5.bas" #line 1 "ftou32reg.asm" #line 1 "neg32.asm" @@ -495,7 +493,7 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A ld a, l ret -#line 364 "opt3_lcd5.bas" +#line 362 "opt3_lcd5.bas" #line 1 "lei16.asm" __LEI16: @@ -514,7 +512,7 @@ checkParity: inc a ; True ret ENDP -#line 365 "opt3_lcd5.bas" +#line 363 "opt3_lcd5.bas" #line 1 "lti16.asm" #line 1 "lei8.asm" @@ -557,7 +555,7 @@ checkParity: inc a ; True ret ENDP -#line 366 "opt3_lcd5.bas" +#line 364 "opt3_lcd5.bas" ZXBASIC_USER_DATA: _x: From 141c4dc35a07c959b00fdf7bc1ddebc008e1596d Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 12 Dec 2017 00:16:51 +0100 Subject: [PATCH 141/247] update ChangeLog file --- ChangeLog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ChangeLog b/ChangeLog index 2b2c9281a..8777c1b2c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +================================================================ +Changes from Version 1.7.2 to 1.8.0 +! Bugfixes in the peephole optimizer (-O3) ++ Better optimized code ++ Improved compiling speed and more stability ++ Fixes minor errors and bugs ++ Now single line IF sentences does not require END IF + ================================================================ Changes from Version 1.7.1 to 1.7.2 ! Bugfixes in libraries esxdos.bas and memcopy.bas From bcf20c7b0fb6a1769e155fac9e549e531d1028e2 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 12 Dec 2017 00:19:08 +0100 Subject: [PATCH 142/247] =?UTF-8?q?Bump=20version:=201.7.2=20=E2=86=92=201?= =?UTF-8?q?.8.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 0303435e6..64d6abfc3 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,4 +1,4 @@ [bumpversion] -current_version = 1.7.2 +current_version = 1.8.0 files = version.py diff --git a/version.py b/version.py index c9ec27fa7..5e2481568 100755 --- a/version.py +++ b/version.py @@ -1 +1 @@ -VERSION = '1.7.2' +VERSION = '1.8.0' From 2391c72c5f78967042e865e89d0e86175e35a529 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Thu, 14 Dec 2017 00:09:56 +0100 Subject: [PATCH 143/247] bugfix: fix crash with some instructions Sometimes the asm might crash upon some assembler wrong code (semantic errors for example), instead of just reporting the error msg. and exiting gracefully. Fixed. --- asmparse.py | 3 +++ tests/functional/test_errmsg.txt | 2 ++ 2 files changed, 5 insertions(+) diff --git a/asmparse.py b/asmparse.py index 56d2b1246..3d291db62 100755 --- a/asmparse.py +++ b/asmparse.py @@ -452,6 +452,9 @@ def add_instruction(self, asm): It will also insert the opcodes at the memory_bytes """ + if gl.has_errors: + return + self.set_memory_slot() self.orgs[self.org] += (asm,) diff --git a/tests/functional/test_errmsg.txt b/tests/functional/test_errmsg.txt index 20ccea4e4..00e02bbb8 100644 --- a/tests/functional/test_errmsg.txt +++ b/tests/functional/test_errmsg.txt @@ -108,4 +108,6 @@ forempty.bas:4: warning: STEP value is 0 and FOR might loop forever fornextopt.bas:4: warning: FOR start value is greater than end. This FOR loop is useless >>> process_file('fornextopt2.bas') fornextopt2.bas:4: warning: FOR start value is lower than end. This FOR loop is useless +>>> process_file('atoloduplbl.asm') +atoloduplbl.asm:3: label '.SetSubScreen' already defined at line 2 From 504e958b916defa0c58f595828121e36b9ea93e8 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Thu, 14 Dec 2017 22:32:01 +0000 Subject: [PATCH 144/247] Merged in bugfix/atoloO1 (pull request #137) bugfix: fix crash with some instructions Sometimes the asm might crash upon some assembler wrong code (semantic errors for example), instead of just reporting the error msg. and exiting gracefully. Fixed. Approved-by: Jose Rodriguez --- tests/functional/atoloduplbl.asm | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 tests/functional/atoloduplbl.asm diff --git a/tests/functional/atoloduplbl.asm b/tests/functional/atoloduplbl.asm new file mode 100644 index 000000000..62b99ae44 --- /dev/null +++ b/tests/functional/atoloduplbl.asm @@ -0,0 +1,4 @@ + +SetSubScreen: +SetSubScreen: +ld (ix+5), 1 From 29dcd0b7b8b16b2507ac23f522d8184628682b5f Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 7 Jan 2018 23:42:58 +0100 Subject: [PATCH 145/247] bugfix: allow binary operators in asm inline When using an inline asm context (ASM ... END ASM) some binary operators like AND (&), OR (|) etc. where not allowed, and they should. Fixed. --- tests/functional/haplo0asm.asm | 47 ++++++++++++++++++++++++++++++++++ tests/functional/haplo0asm.bas | 14 ++++++++++ zxbasmpplex.py | 2 +- zxbpplex.py | 2 +- 4 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 tests/functional/haplo0asm.asm create mode 100644 tests/functional/haplo0asm.bas diff --git a/tests/functional/haplo0asm.asm b/tests/functional/haplo0asm.asm new file mode 100644 index 000000000..0580c0c97 --- /dev/null +++ b/tests/functional/haplo0asm.asm @@ -0,0 +1,47 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei +#line 0 + tablaColor equ 2 + tablaColorAlto equ tablaColor >> 8 + tablaColorBajo equ tablaColor & 0xFF + tablaColorCheck equ (tablaColorAlto << 8) | tablaColorBajo + tabla1 equ tablaColor + 1 + tabla2 equ tablaColor ^ 2 + tabla3 equ tablaColor % 3 + tabla4 equ tablaColor ~ 5 + ld a, tablaColorAlto + ld b, tablaColorBajo +#line 10 + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/haplo0asm.bas b/tests/functional/haplo0asm.bas new file mode 100644 index 000000000..90393cac9 --- /dev/null +++ b/tests/functional/haplo0asm.bas @@ -0,0 +1,14 @@ +asm +tablaColor equ 2 +tablaColorAlto equ tablaColor >> 8 +tablaColorBajo equ tablaColor & 0xFF +tablaColorCheck equ (tablaColorAlto << 8) | tablaColorBajo +tabla1 equ tablaColor + 1 +tabla2 equ tablaColor ^ 2 +tabla3 equ tablaColor % 3 +tabla4 equ tablaColor ~ 5 + +ld a, tablaColorAlto +ld b, tablaColorBajo +end asm + diff --git a/zxbasmpplex.py b/zxbasmpplex.py index b659e2d45..f97bc9dd3 100755 --- a/zxbasmpplex.py +++ b/zxbasmpplex.py @@ -105,7 +105,7 @@ def t_INITIAL_CHAR(self, t): return t def t_INITIAL_TOKEN(self, t): - r"[][%',.:$()*/<>~&|+-]" + r"[][%',.:$()*/<>~&|+^-]" return t def t_prepro_define_defargs_defargsopt_defexpr_pragma_NEWLINE(self, t): diff --git a/zxbpplex.py b/zxbpplex.py index a5de6149f..6eb148b4d 100755 --- a/zxbpplex.py +++ b/zxbpplex.py @@ -122,7 +122,7 @@ def t_asm_CHAR(self, t): return t def t_asm_TOKEN(self, t): - r"[][',.:$()*/+-]" + r"[][',.:$()*/+<>|&~%^-]" return t def t_INITIAL_CONTINUE(self, t): From f35a4b6a20bcef19d0881d55a04f3f916b8a2d8a Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 12 Jan 2018 21:28:17 +0100 Subject: [PATCH 146/247] bugfix: prevent potential bugfix in memcopy lib The push af / pop af sequence might be corrupted if an interruption happens between them. Uses hl' instead. Also adds MemSet() routine --- library/memcopy.bas | 60 ++++++++++++++++++++++++++++----- tests/functional/memcpytest.asm | 50 ++++++++++++++++++++------- tox.ini | 2 -- 3 files changed, 89 insertions(+), 23 deletions(-) diff --git a/library/memcopy.bas b/library/memcopy.bas index 4569c7e69..6e72c152b 100644 --- a/library/memcopy.bas +++ b/library/memcopy.bas @@ -1,8 +1,10 @@ ' ---------------------------------------------------------------- ' This file is released under the MIT License ' -' Copyleft (k) 2008 -' by Jose Rodriguez-Rosa (a.k.a. Boriel) +' Copyleft (k) 2008-2018 +' Contributed by: +' - Jose Rodriguez-Rosa (a.k.a. Boriel) +' - Miguel Angel Diaz-Jodar (a.k.a. McLeod_Ideafix) ' ---------------------------------------------------------------- #ifndef __LIBRARY_MEMCOPY__ @@ -34,11 +36,14 @@ sub fastcall MemMove(source as uinteger, dest as uinteger, length as uinteger) ; DE => Start of destiny block ; BC => Block length - pop af ; ret addr - pop de ; dest - pop bc ; length - push af ; stores ret addr back - + exx + pop hl ; uses HL' to preserve HL + exx + pop de ; dest + pop bc ; length + exx + push hl ; stores ret addr back + exx jp __MEMCPY end asm end sub @@ -65,15 +70,52 @@ sub fastcall MemCopy(source as uinteger, dest as uinteger, length as uinteger) ; DE => Start of destiny block ; BC => Block length - pop af ; ret addr + exx + pop hl ; uses HL' to preserve HL + exx pop de ; dest pop bc ; length - push af ; stores ret addr back + exx + push hl ; stores ret addr back + exx ldir end asm end sub +' ---------------------------------------------------------------- +' Sub MemSet(destaddr, value, blocklength) +' +' Parameters: +' destaddr: memory address of destiny block to fill +' value: value to fill with +' length: number of bytes to fill +' +' ---------------------------------------------------------------- +sub fastcall MemSet(dest as uinteger, value as ubyte, length as uinteger) + asm + +; HL => Start of destination block +; DE => Value (D) +; BC => Block length + + pop de ; ret addr + pop af ; value + pop bc ; length + push de ; stores ret addr back + ld (hl),a + dec bc + ld a, b + or c + ret z + ld d,h + ld e,l + inc de + ldir + end asm +end sub + + #require "memcopy.asm" #pragma pop(case_insensitive) diff --git a/tests/functional/memcpytest.asm b/tests/functional/memcpytest.asm index 1007f2b78..ca931ade4 100644 --- a/tests/functional/memcpytest.asm +++ b/tests/functional/memcpytest.asm @@ -64,25 +64,51 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 _MemMove: -#line 28 - pop af +#line 30 + exx + pop hl + exx pop de pop bc - push af + exx + push hl + exx jp __MEMCPY -#line 33 +#line 39 _MemMove__leave: ret _MemCopy: -#line 59 - pop af +#line 64 + exx + pop hl + exx pop de pop bc - push af + exx + push hl + exx ldir -#line 64 +#line 73 _MemCopy__leave: ret +_MemSet: +#line 95 + pop de + pop af + pop bc + push de + ld (hl),a + dec bc + ld a, b + or c + ret z + ld d,h + ld e,l + inc de + ldir +#line 108 +_MemSet__leave: + ret __LABEL5: DEFW 0005h DEFB 54h @@ -172,7 +198,7 @@ __CLS_SCR: ; to get the start of the screen ENDP -#line 78 "memcpytest.bas" +#line 104 "memcpytest.bas" #line 1 "memcopy.asm" ; ---------------------------------------------------------------- @@ -224,7 +250,7 @@ __MEMCPY2: ret ENDP -#line 79 "memcpytest.bas" +#line 105 "memcpytest.bas" #line 1 "pause.asm" ; The PAUSE statement (Calling the ROM) @@ -233,7 +259,7 @@ __PAUSE: ld b, h ld c, l jp 1F3Dh ; PAUSE_1 -#line 80 "memcpytest.bas" +#line 106 "memcpytest.bas" #line 1 "printstr.asm" #line 1 "print.asm" @@ -1650,7 +1676,7 @@ __PRINT_STR: ENDP -#line 81 "memcpytest.bas" +#line 107 "memcpytest.bas" ZXBASIC_USER_DATA: _i: diff --git a/tox.ini b/tox.ini index 4e1fffb00..9870adcba 100644 --- a/tox.ini +++ b/tox.ini @@ -10,8 +10,6 @@ deps = -rrequirements.txt commands = py.test \ - --cov-report html:htmlcov/{envname} \ - --cov . \ {posargs} [flake8] From ea81121c46796dab894a50a3b44fb11612771803 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 15 Jan 2018 23:44:52 +0100 Subject: [PATCH 147/247] Improve radastan mode routines * Adds MakeRGB which converts R, G, B color to byte * Potential Bugfix in RadastanPalette (remove useless OUT) --- library/radastan.bas | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/library/radastan.bas b/library/radastan.bas index bcd2d6030..67cbe228a 100644 --- a/library/radastan.bas +++ b/library/radastan.bas @@ -29,13 +29,27 @@ dummy = RadastanScrAddr + RadastanColRow + RadastanFontAddr ' ' Parameters: ' enable: 0 => disable (normal mode), otherwise radastan mode -'' ---------------------------------------------------------------- +' ---------------------------------------------------------------- sub RadastanMode(enable as Ubyte) OUT 64571, 64 OUT 64827, 3 * SGN(enable) end sub +' ---------------------------------------------------------------- +' function MakeRGB +' Converts an R, G, B color to a byte +' +' Parameters: +' r: Red component +' g: Green component +' b: Blue component +' ---------------------------------------------------------------- +function MakeRGB (r as ubyte, g as ubyte, b as ubyte) as ubyte + return ((g band 7) shl 5) bor ((r band 7) shl 2) bor (b band 3) +end function + + ' ---------------------------------------------------------------- ' Sub RadastanPlot ' @@ -347,7 +361,6 @@ END SUB ' rgb: Color value rgb = binary GGGRRRBB ' ---------------------------------------------------------------- SUB RadastanPalette(ByVal colorIndex as Ubyte, ByVal rgb as UByte) ' - OUT 48955, 64: OUT 65339, 1 OUT 48955, colorIndex: OUT 65339, rgb END SUB From 319cdeac92a657329a50dab99fac930b34fab5df Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 15 Jan 2018 23:54:15 +0100 Subject: [PATCH 148/247] restores tox.ini back Adds 2 lines accidentally removed in the previous commits --- tox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tox.ini b/tox.ini index 9870adcba..4e1fffb00 100644 --- a/tox.ini +++ b/tox.ini @@ -10,6 +10,8 @@ deps = -rrequirements.txt commands = py.test \ + --cov-report html:htmlcov/{envname} \ + --cov . \ {posargs} [flake8] From d483d899357c9a6c3a4cc3f181b74798c27b216c Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 23 Jan 2018 00:32:29 +0100 Subject: [PATCH 149/247] bugfix: enable-break The --enable-break flag corrupted HL and A registers which can overwrite function returned values (Byte and Words returned ones). --- arch/zx48k/translator.py | 1 + library-asm/break.asm | 15 ++-- tests/functional/break.asm | 143 +++++++++++++++++++++++++++++++++++++ tests/functional/break.bas | 10 +++ zxbparser.py | 36 ++++++---- 5 files changed, 187 insertions(+), 18 deletions(-) create mode 100644 tests/functional/break.asm create mode 100644 tests/functional/break.bas diff --git a/arch/zx48k/translator.py b/arch/zx48k/translator.py index f8e868729..923cea7aa 100644 --- a/arch/zx48k/translator.py +++ b/arch/zx48k/translator.py @@ -819,6 +819,7 @@ def visit_ON_GOSUB(self, node): def visit_CHKBREAK(self, node): if self.PREV_TOKEN != node.token: + self.emit('inline', 'push hl', node.children[0].t) self.emit('fparam' + self.TSUFFIX(gl.PTR_TYPE), node.children[0].t) self.emit('call', 'CHECK_BREAK', 0) backend.REQUIRES.add('break.asm') diff --git a/library-asm/break.asm b/library-asm/break.asm index 6ded698f2..ae8570858 100644 --- a/library-asm/break.asm +++ b/library-asm/break.asm @@ -8,14 +8,21 @@ CHECK_BREAK: PROC - LOCAL PPC, TS_BRK + LOCAL PPC, TS_BRK, NO_BREAK + push af call TS_BRK - ret c + jr c, NO_BREAK - ld (PPC), HL + ld (PPC), hl ; line num ld a, ERROR_BreakIntoProgram - jp __ERROR + jp __ERROR ; this stops the program and exits to BASIC + +NO_BREAK: + pop af + pop hl ; ret address + ex (sp), hl ; puts it back into the stack and recovers initial HL + ret PPC EQU 23621 TS_BRK EQU 8020 diff --git a/tests/functional/break.asm b/tests/functional/break.asm new file mode 100644 index 000000000..3da3dfcfd --- /dev/null +++ b/tests/functional/break.asm @@ -0,0 +1,143 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei +__LABEL__10: +#line 4 + push hl +#line 5 + ld hl, 4 + call CHECK_BREAK +__LABEL__20: + ld a, 1 + ld (_a), a +#line 5 + push hl +#line 6 + ld hl, 5 + call CHECK_BREAK +__LABEL__30: + ld a, 2 + ld (_a), a + inc a + ld (_a), a +#line 6 + push hl +#line 7 + ld hl, 6 + call CHECK_BREAK + ld a, 40 + ld (_a), a +#line 10 + push hl +#line 11 + ld hl, 10 + call CHECK_BREAK + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "break.asm" + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 2 "break.asm" + + + ; Check if BREAK is pressed + ; Return if not. Else Raises + ; L BREAK Into Program Error + ; HL contains the line number we want to appear in the error msg. + +CHECK_BREAK: + PROC + LOCAL PPC, TS_BRK, NO_BREAK + + push af + call TS_BRK + jr c, NO_BREAK + + ld (PPC), hl ; line num + ld a, ERROR_BreakIntoProgram + jp __ERROR ; this stops the program and exits to BASIC + +NO_BREAK: + pop af + pop hl ; ret address + ex (sp), hl ; puts it back into the stack and recovers initial HL + ret + + PPC EQU 23621 + TS_BRK EQU 8020 + + ENDP + +#line 49 "break.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/break.bas b/tests/functional/break.bas new file mode 100644 index 000000000..baa7aecce --- /dev/null +++ b/tests/functional/break.bas @@ -0,0 +1,10 @@ +#pragma enableBreak = true +:REM Keyboard BREAK interrupt generation + +10 DIM a as UByte +20 a = 1 +30 a = 2: a = a + 1 + + + +a = 40 diff --git a/zxbparser.py b/zxbparser.py index eb2797f43..16d0cbaf7 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -104,6 +104,11 @@ # ---------------------------------------------------------------------- PRINT_IS_USED = False +# ---------------------------------------------------------------------- +# Last line number output for checking program key board BREAK +# ---------------------------------------------------------------------- +last_brk_linenum = 0 + def init(): """ Initializes parser state @@ -117,10 +122,12 @@ def init(): global data_ast global optemps global OPTIONS + global last_brk_linenum LABELS = {} LET_ASSIGNMENT = False PRINT_IS_USED = False + last_brk_linenum = 0 ast = None data_ast = None # Global Variables AST @@ -383,6 +390,19 @@ def make_label(id_, lineno): return entry +def make_break(lineno, p): + """ Checks if --enable-break is set, and if so, calls + BREAK keyboard interruption for this line if it has not been already + checked """ + global last_brk_linenum + + if not OPTIONS.enableBreak.value or lineno == last_brk_linenum or is_null(p): + return None + + last_brk_linenum = lineno + return make_sentence('CHKBREAK', make_number(lineno, lineno, TYPE.uinteger)) + + # ---------------------------------------------------------------------- # Operators precedence # ---------------------------------------------------------------------- @@ -466,25 +486,13 @@ def p_start(p): def p_program_program_line(p): """ program : program_line """ - if OPTIONS.enableBreak.value: - lineno = p.lexer.lineno - tmp = make_sentence('CHKBREAK', - make_number(lineno, lineno, TYPE.uinteger)) - p[0] = make_block(p[1], tmp) - else: - p[0] = make_block(p[1]) + p[0] = make_block(p[1], make_break(p.lineno(1), p[1])) def p_program(p): """ program : program program_line """ - if OPTIONS.enableBreak.value: - lineno = p.lexer.lineno - tmp = make_sentence('CHKBREAK', - make_number(lineno, lineno, TYPE.uinteger)) - p[0] = make_block(p[1], p[2], tmp) - else: - p[0] = make_block(p[1], p[2]) + p[0] = make_block(p[1], p[2], make_break(p.lineno(2), p[2])) def p_program_line(p): From cc2c717b200d42912588ed17f806c5c6d56a6875 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 23 Jan 2018 23:19:39 +0100 Subject: [PATCH 150/247] bugfix: fixes an issue with keyboard and input lib This patch ensures it works on all models. --- library/input.bas | 1 + 1 file changed, 1 insertion(+) diff --git a/library/input.bas b/library/input.bas index 54e61f48a..abb2ae04c 100644 --- a/library/input.bas +++ b/library/input.bas @@ -29,6 +29,7 @@ FUNCTION input(MaxLen AS UINTEGER) AS STRING DIM i as UINTEGER result$ = "" + POKE 23611, PEEK 23611 bOR 8 DO PRIVATEInputShowCursor() From 9e2b4e7891e1d1d7034caa66906a2e79d83b3b06 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Thu, 25 Jan 2018 00:21:28 +0100 Subject: [PATCH 151/247] fix permissions to non-exec --- tests/functional/ifcrash.bas | 0 tests/functional/nir.bas | 0 tests/functional/rman.bas | 0 3 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 tests/functional/ifcrash.bas mode change 100755 => 100644 tests/functional/nir.bas mode change 100755 => 100644 tests/functional/rman.bas diff --git a/tests/functional/ifcrash.bas b/tests/functional/ifcrash.bas old mode 100755 new mode 100644 diff --git a/tests/functional/nir.bas b/tests/functional/nir.bas old mode 100755 new mode 100644 diff --git a/tests/functional/rman.bas b/tests/functional/rman.bas old mode 100755 new mode 100644 From c80a83aa54f693666fed533465e1ccd9bb8027cd Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Thu, 25 Jan 2018 00:16:15 +0100 Subject: [PATCH 152/247] bugfix: macro parameters not working in asm scope When using inline ASM blocks, macro parameters were being ignored. Fixed. --- tests/functional/emook0.bi | 8 ++++++++ tests/functional/emook0.out | 11 +++++++++++ zxbpplex.py | 10 +++++----- 3 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 tests/functional/emook0.bi create mode 100644 tests/functional/emook0.out diff --git a/tests/functional/emook0.bi b/tests/functional/emook0.bi new file mode 100644 index 000000000..980656268 --- /dev/null +++ b/tests/functional/emook0.bi @@ -0,0 +1,8 @@ +#define SetREG(reg,val) \ + LD A,reg \ + LD BC,val + +ASM + SetREG(A,254) +end Asm + diff --git a/tests/functional/emook0.out b/tests/functional/emook0.out new file mode 100644 index 000000000..7fb90e2bb --- /dev/null +++ b/tests/functional/emook0.out @@ -0,0 +1,11 @@ +#line 1 "emook0.bi" + + +ASM + + LD A,A + LD BC,254 +#line 6 + +end Asm + diff --git a/zxbpplex.py b/zxbpplex.py index 6eb148b4d..f829bb964 100755 --- a/zxbpplex.py +++ b/zxbpplex.py @@ -117,12 +117,12 @@ def t_asm_ID(self, t): return t def t_asm_CHAR(self, t): - r"'([^'\n]|'')'" + r"'[^'\n]|'''" t.type = 'TOKEN' return t def t_asm_TOKEN(self, t): - r"[][',.:$()*/+<>|&~%^-]" + r"[]['.:$*/+<>|&~%^-]" return t def t_INITIAL_CONTINUE(self, t): @@ -248,11 +248,11 @@ def t_pragma_RP(self, t): r'\)' return t - def t_INITIAL_defexpr_if_LLP(self, t): + def t_INITIAL_asm_defexpr_if_LLP(self, t): r'\(' return t - def t_INITIAL_defexpr_if_RRP(self, t): + def t_INITIAL_asm_defexpr_if_RRP(self, t): r'\)' return t @@ -322,7 +322,7 @@ def t_pragma_EQ(self, t): r'=' return t - def t_INITIAL_defexpr_defargs_prepro_COMMA(self, t): + def t_INITIAL_asm_defexpr_defargs_prepro_COMMA(self, t): r',' return t From 842d3a2cc1071296fa044bf760060ac4fa5c44fc Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 27 Jan 2018 00:25:09 +0100 Subject: [PATCH 153/247] bugfix: missing attribute initialization for LABEL When converting a VAR to LABEL the field _scope_owner must be initialized. --- symbols/var.py | 1 + tests/functional/lcd_crash.asm | 192 +++++++++++++++++++++++++++++++++ tests/functional/lcd_crash.bas | 14 +++ 3 files changed, 207 insertions(+) create mode 100644 tests/functional/lcd_crash.asm create mode 100644 tests/functional/lcd_crash.bas diff --git a/symbols/var.py b/symbols/var.py index 7403893b3..f5af8d746 100644 --- a/symbols/var.py +++ b/symbols/var.py @@ -135,6 +135,7 @@ def to_label(var_instance): from symbols import LABEL var_instance.__class__ = LABEL var_instance.class_ = CLASS.label + var_instance._scope_owner = [] return var_instance @staticmethod diff --git a/tests/functional/lcd_crash.asm b/tests/functional/lcd_crash.asm new file mode 100644 index 000000000..f27044d00 --- /dev/null +++ b/tests/functional/lcd_crash.asm @@ -0,0 +1,192 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, __LABEL__void + ld (_tiles + 3), hl + ld (_tiles + 5), hl +__LABEL__void: + xor a + push af + xor a + push af + xor a + push af + call _settile + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +_putChars: + push ix + ld ix, 0 + add ix, sp +_putChars__leave: + ld sp, ix + pop ix + exx + pop hl + pop bc + pop bc + pop bc + pop bc + ex (sp), hl + exx + ret +_settile: + push ix + ld ix, 0 + add ix, sp + ld hl, __LABEL__void + push hl + ld a, 3 + push af + ld a, 3 + push af + ld a, (_monsterx) + ld h, 3 + call __MUL8_FAST + ld l, a + add a, a + sbc a, a + ld h, a + push hl + ld a, (_monsterx) + ld h, 3 + call __MUL8_FAST + ld l, a + add a, a + sbc a, a + ld h, a + push hl + call _putChars +_settile__leave: + ld sp, ix + pop ix + exx + pop hl + pop bc + pop bc + ex (sp), hl + exx + ret +#line 1 "mul8.asm" + +__MUL8: ; Performs 8bit x 8bit multiplication + PROC + + ;LOCAL __MUL8A + LOCAL __MUL8LOOP + LOCAL __MUL8B + ; 1st operand (byte) in A, 2nd operand into the stack (AF) + pop hl ; return address + ex (sp), hl ; CALLE convention + +;;__MUL8_FAST: ; __FASTCALL__ entry + ;; ld e, a + ;; ld d, 0 + ;; ld l, d + ;; + ;; sla h + ;; jr nc, __MUL8A + ;; ld l, e + ;; +;;__MUL8A: + ;; + ;; ld b, 7 +;;__MUL8LOOP: + ;; add hl, hl + ;; jr nc, __MUL8B + ;; + ;; add hl, de + ;; +;;__MUL8B: + ;; djnz __MUL8LOOP + ;; + ;; ld a, l ; result = A and HL (Truncate to lower 8 bits) + +__MUL8_FAST: ; __FASTCALL__ entry, a = a * h (8 bit mul) and Carry + + ld b, 8 + ld l, a + xor a + +__MUL8LOOP: + add a, a ; a *= 2 + sla l + jp nc, __MUL8B + add a, h + +__MUL8B: + djnz __MUL8LOOP + + ret ; result = HL + ENDP + +#line 82 "lcd_crash.bas" + +ZXBASIC_USER_DATA: +_monsterx: + DEFB 00 +_tiles: + DEFW 0000h + DEFB 02h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/lcd_crash.bas b/tests/functional/lcd_crash.bas new file mode 100644 index 000000000..6e6adc875 --- /dev/null +++ b/tests/functional/lcd_crash.bas @@ -0,0 +1,14 @@ +dim tiles(16) as uinteger +tiles(0)=@void +tiles(1)=tiles(0) + +dim monsterx as byte +void: + +sub putChars(x as Uinteger, y as Uinteger, a as Ubyte, b as Ubyte, addr as Uinteger) +end Sub + +sub settile(x as ubyte,y as ubyte,tile as ubyte) + putChars(monsterx*3,monsterx*3,3,3,@void) +end sub +settile(0, 0, 0) From b31e3cf0711433a1d1baae6ac4c82c645c93aaaa Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 29 Jan 2018 00:16:49 +0100 Subject: [PATCH 154/247] bugfix: crash with -O3 (optimizer). Fixed. Under some (rare) circumnstances the -O3 peephole optimizer might crash. Fixed. --- arch/zx48k/optimizer.py | 3 ++ tests/functional/opt3_lcd_o3_crash.asm | 59 ++++++++++++++++++++++++++ tests/functional/opt3_lcd_o3_crash.bas | 18 ++++++++ 3 files changed, 80 insertions(+) create mode 100644 tests/functional/opt3_lcd_o3_crash.asm create mode 100644 tests/functional/opt3_lcd_o3_crash.bas diff --git a/arch/zx48k/optimizer.py b/arch/zx48k/optimizer.py index 9fbb0df9f..d8aac69c1 100644 --- a/arch/zx48k/optimizer.py +++ b/arch/zx48k/optimizer.py @@ -495,6 +495,9 @@ def set(self, r, val): def get(self, r): """ Returns precomputed value of the given expression """ + if r is None: + return None + if r.lower() == '(sp)' and self.stack: return self.stack[-1] diff --git a/tests/functional/opt3_lcd_o3_crash.asm b/tests/functional/opt3_lcd_o3_crash.asm new file mode 100644 index 000000000..fc23583f1 --- /dev/null +++ b/tests/functional/opt3_lcd_o3_crash.asm @@ -0,0 +1,59 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call _Drawscreen +__LABEL__Shoottable1: +__LABEL__Shoottable2: +__LABEL__UDGs01: +__LABEL__Buffer: + ld bc, 0 +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + pop iy + pop ix + exx + ei + ret +__CALL_BACK__: + DEFW 0 +_Drawscreen: + push ix + ld ix, 0 + add ix, sp + ld hl, 0 + push hl + inc sp + ld (ix-1), 0 + jp __LABEL0 +__LABEL3: + inc (ix-1) +__LABEL0: + ld a, (ix-1) + ld h, a + ld a, 21 + cp h + jp nc, __LABEL3 +_Drawscreen__leave: + ld sp, ix + pop ix + ret + +ZXBASIC_USER_DATA: + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/opt3_lcd_o3_crash.bas b/tests/functional/opt3_lcd_o3_crash.bas new file mode 100644 index 000000000..42bf469a2 --- /dev/null +++ b/tests/functional/opt3_lcd_o3_crash.bas @@ -0,0 +1,18 @@ +dim control$,key$ as string +dim posx,posy,dir,drw,found as byte +dim shtx,shty,shard as Uinteger + +sub Drawscreen() + dim x as ubyte + dim adr as uinteger + adr=@Buffer + for x=0 to 21 + next x +end sub + +Drawscreen() + +Shoottable1: +Shoottable2: +UDGs01: +Buffer: From 9d42efb040dc2cbf539e6dcac61322b301dd0668 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 30 Jan 2018 00:01:05 +0100 Subject: [PATCH 155/247] bugfix: correctly emit OUT instruction Was not correctly emitting operators and corrupting the stack. Also the test timeout has been raised to 15 seconds since pypy sometimes fails. --- arch/zx48k/backend/__init__.py | 90 +++++++++++++++++++++++----------- tests/functional/haplo_out.asm | 42 ++++++++++++++++ tests/functional/haplo_out.bas | 4 ++ tests/functional/test_basic.py | 2 +- 4 files changed, 109 insertions(+), 29 deletions(-) create mode 100644 tests/functional/haplo_out.asm create mode 100644 tests/functional/haplo_out.bas diff --git a/arch/zx48k/backend/__init__.py b/arch/zx48k/backend/__init__.py index 9dd89269c..fd4f6ea47 100644 --- a/arch/zx48k/backend/__init__.py +++ b/arch/zx48k/backend/__init__.py @@ -120,6 +120,7 @@ OPT19 = True OPT21 = True OPT22 = True +OPT23 = True # Label RegExp RE_LABEL = re.compile('^[ \t]*[a-zA-Z_][_a-zA-Z\d]*:') @@ -600,21 +601,10 @@ def _lvard(ins): def _out(ins): """ Translates OUT to asm. """ - output = [] - - value = ins.quad[2] - try: - value = int(value) & 255 # Converted to byte - output.append('ld a, %i' % value) - except ValueError: - output.append('pop af') - - try: - port = int(ins.quad[1]) & 0xFFFF # Converted to word - output.append('ld bc, %i' % port) - except ValueError: - output.append('pop bc') - + output = _8bit_oper(ins.quad[2]) + output.extend(_16bit_oper(ins.quad[1])) + output.append('ld b, h') + output.append('ld c, l') output.append('out (c), a') return output @@ -623,14 +613,9 @@ def _out(ins): def _in(ins): """ Translates IN to asm. """ - output = [] - - try: - port = int(ins.quad[1]) & 0xFFFF # Converted to word - output.append('ld bc, %i' % port) - except ValueError: - output.append('pop bc') - + output = _16bit_oper(ins.quad[1]) + output.append('ld b, h') + output.append('ld c, l') output.append('in a, (c)') output.append('push af') @@ -2368,13 +2353,16 @@ def output_join(output, new_chunk): """ changed = True and OPTIONS.optimization.value > 0 # Only enter here if -O0 was not set - while changed and len(new_chunk) > 0 and len(output) > 0: - a1 = output[-1] # Last output instruction - a2 = new_chunk[0] # Fist new output instruction + while changed and new_chunk: + if output: + a1 = output[-1] # Last output instruction + i1 = inst(a1) + o1 = oper(a1) + else: + a1 = i1 = o1 = None - i1 = inst(a1) + a2 = new_chunk[0] # Fist new output instruction i2 = inst(a2) - o1 = oper(a1) o2 = oper(a2) if OPT00 and i2[-1] == ':': @@ -2561,6 +2549,52 @@ def output_join(output, new_chunk): changed = True continue + # Converts: + # ld hl, (NN) | ld hl, NN | pop hl + # ld b, h + # ld c, l + # in a, (c) + # Into: + # ld bc, (NN) | ld bc, NN | pop bc + # in a, (c) + if OPT23 and len(new_chunk) > 3 and inst(new_chunk[3]) == 'in': + ia = inst(new_chunk[1]) + oa = oper(new_chunk[1]) + ib = inst(new_chunk[2]) + ob = oper(new_chunk[2]) + if (ia, oa[0], oa[1], ib, ob[0], ob[1]) == ('ld', 'b', 'h', 'ld', 'c', 'l'): + ii = inst(new_chunk[0]) + oi = oper(new_chunk[0]) + if ii in ('pop', 'ld') and oi[0] == 'hl': + new_chunk[0] = ii + ' ' + 'bc' + (', %s' % oi[1] if ii == 'ld' else '') + new_chunk.pop(1) + new_chunk.pop(1) + changed = True + continue + + # Converts: + # ld hl, (NN) | ld hl, NN | pop hl + # ld b, h + # ld c, l + # out (c), a + # Into: + # ld bc, (NN) | ld bc, NN | pop bc + # out (c), a + if OPT23 and len(new_chunk) > 3 and inst(new_chunk[-1]) == 'out': + ia = inst(new_chunk[-3]) + oa = oper(new_chunk[-3]) + ib = inst(new_chunk[-2]) + ob = oper(new_chunk[-2]) + if (ia, oa[0], oa[1], ib, ob[0], ob[1]) == ('ld', 'b', 'h', 'ld', 'c', 'l'): + ii = inst(new_chunk[-4]) + oi = oper(new_chunk[-4]) + if ii in ('pop', 'ld') and oi[0] == 'hl': + new_chunk[-4] = ii + ' ' + 'bc' + (', %s' % oi[1] if ii == 'ld' else '') + new_chunk.pop(-2) + new_chunk.pop(-2) + changed = True + continue + changed, new_chunk = optiblock(new_chunk) output.extend(new_chunk) diff --git a/tests/functional/haplo_out.asm b/tests/functional/haplo_out.asm new file mode 100644 index 000000000..710da8340 --- /dev/null +++ b/tests/functional/haplo_out.asm @@ -0,0 +1,42 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld a, (_a) + ld bc, (_b) + out (c), a + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 +_b: + DEFB 00, 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/haplo_out.bas b/tests/functional/haplo_out.bas new file mode 100644 index 000000000..3f8a56422 --- /dev/null +++ b/tests/functional/haplo_out.bas @@ -0,0 +1,4 @@ +DIM a as UByte +DIM b as Uinteger +OUT b, a + diff --git a/tests/functional/test_basic.py b/tests/functional/test_basic.py index 9318f89c2..90c204429 100755 --- a/tests/functional/test_basic.py +++ b/tests/functional/test_basic.py @@ -11,7 +11,7 @@ @pytest.mark.parametrize('fname', [os.path.join(TEST_PATH, f) for f in os.listdir(TEST_PATH) if f.endswith(".bas")]) -@pytest.mark.timeout(5) +@pytest.mark.timeout(15) def test_basic(fname): test.main(['-d', '-e', '/dev/null', fname]) if test.COUNTER == 0: From 4da41db7ff47e988baf2bb9981cc40d567374d9e Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 30 Jan 2018 20:36:39 +0100 Subject: [PATCH 156/247] improvement: optimizes AND (boolean) instruction This is faster and takes only un extra byte per operand. In the future, a --optmize-for-speed (of for memory) is used then the old scheme can be recovered to save one byte (at the cost of higher overhead). --- arch/zx48k/backend/__8bit.py | 9 +++++++-- tests/functional/and8.asm | 19 ++++--------------- tests/functional/ifcrash.asm | 29 +++++++++-------------------- tests/functional/opt3_lcd5.asm | 23 ++++++++++++++++------- 4 files changed, 36 insertions(+), 44 deletions(-) diff --git a/arch/zx48k/backend/__8bit.py b/arch/zx48k/backend/__8bit.py index 7932dc02c..625794830 100644 --- a/arch/zx48k/backend/__8bit.py +++ b/arch/zx48k/backend/__8bit.py @@ -749,9 +749,14 @@ def _and8(ins): return output output = _8bit_oper(op1, op2) - output.append('call __AND8') + # output.append('call __AND8') + lbl = tmp_label() + output.append('or a') + output.append('jr z, %s' % lbl) + output.append('ld a, h') + output.append('%s:' % lbl) output.append('push af') - REQUIRES.add('and8.asm') + # REQUIRES.add('and8.asm') return output diff --git a/tests/functional/and8.asm b/tests/functional/and8.asm index 134680a99..c890d1ef9 100644 --- a/tests/functional/and8.asm +++ b/tests/functional/and8.asm @@ -22,7 +22,10 @@ __START_PROGRAM: ld (_b), a ld hl, (_a - 1) ld a, (_a) - call __AND8 + or a + jr z, __LABEL0 + ld a, h +__LABEL0: ld (_b), a ld hl, 0 ld b, h @@ -40,20 +43,6 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 -#line 1 "and8.asm" - - ; FASTCALL boolean and 8 version. - ; result in Accumulator (0 False, not 0 True) -; __FASTCALL__ version (operands: A, H) - ; Performs 8bit and 8bit and returns the boolean - -__AND8: - or a - ret z - ld a, h - ret - -#line 32 "and8.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/ifcrash.asm b/tests/functional/ifcrash.asm index 06fcb91c0..8a467c559 100644 --- a/tests/functional/ifcrash.asm +++ b/tests/functional/ifcrash.asm @@ -42,7 +42,10 @@ __START_PROGRAM: call __EQF ld h, a pop af - call __AND8 + or a + jr z, __LABEL6 + ld a, h +__LABEL6: or a jp z, __LABEL5 ld a, (_nsfx) @@ -94,20 +97,6 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 -#line 1 "and8.asm" - - ; FASTCALL boolean and 8 version. - ; result in Accumulator (0 False, not 0 True) -; __FASTCALL__ version (operands: A, H) - ; Performs 8bit and 8bit and returns the boolean - -__AND8: - or a - ret z - ld a, h - ret - -#line 86 "ifcrash.bas" #line 1 "eqf.asm" #line 1 "u32tofreg.asm" @@ -385,7 +374,7 @@ __EQF: ; A = B call __FPSTACK_POP jp __FTOU8 ; Convert to 8 bits -#line 87 "ifcrash.bas" +#line 89 "ifcrash.bas" #line 1 "gtf.asm" @@ -415,7 +404,7 @@ __GTF: ; A > B call __FPSTACK_POP jp __FTOU8; Convert to 8 bits -#line 89 "ifcrash.bas" +#line 91 "ifcrash.bas" #line 1 "pushf.asm" @@ -446,7 +435,7 @@ __FP_PUSH_REV: ret -#line 90 "ifcrash.bas" +#line 92 "ifcrash.bas" #line 1 "storef.asm" __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) @@ -477,7 +466,7 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), b ret -#line 91 "ifcrash.bas" +#line 93 "ifcrash.bas" #line 1 "subf.asm" @@ -504,7 +493,7 @@ __SUBF: ; Subtraction jp __FPSTACK_POP -#line 92 "ifcrash.bas" +#line 94 "ifcrash.bas" ZXBASIC_USER_DATA: _KEYSPACE: diff --git a/tests/functional/opt3_lcd5.asm b/tests/functional/opt3_lcd5.asm index a43a21965..7e643c63c 100644 --- a/tests/functional/opt3_lcd5.asm +++ b/tests/functional/opt3_lcd5.asm @@ -70,7 +70,10 @@ _ScanField: call __LTI16 ld h, a pop af - call __AND8 + or a + jr z, __LABEL6 + ld a, h +__LABEL6: push af ld l, (ix+6) ld h, (ix+7) @@ -79,7 +82,10 @@ _ScanField: call __LEI16 ld h, a pop af - call __AND8 + or a + jr z, __LABEL7 + ld a, h +__LABEL7: push af ld l, (ix+6) ld h, (ix+7) @@ -87,7 +93,10 @@ _ScanField: call __LTI16 ld h, a pop af - call __AND8 + or a + jr z, __LABEL8 + ld a, h +__LABEL8: or a jp z, __LABEL0 ld hl, __LABEL__overlay @@ -382,7 +391,7 @@ __AND8: ld a, h ret -#line 361 "opt3_lcd5.bas" +#line 370 "opt3_lcd5.bas" #line 1 "ftou32reg.asm" #line 1 "neg32.asm" @@ -493,7 +502,7 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A ld a, l ret -#line 362 "opt3_lcd5.bas" +#line 371 "opt3_lcd5.bas" #line 1 "lei16.asm" __LEI16: @@ -512,7 +521,7 @@ checkParity: inc a ; True ret ENDP -#line 363 "opt3_lcd5.bas" +#line 372 "opt3_lcd5.bas" #line 1 "lti16.asm" #line 1 "lei8.asm" @@ -555,7 +564,7 @@ checkParity: inc a ; True ret ENDP -#line 364 "opt3_lcd5.bas" +#line 373 "opt3_lcd5.bas" ZXBASIC_USER_DATA: _x: From 8f7b5eea9d52ee6bc3f59093b838ad68353791d1 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 30 Jan 2018 20:43:03 +0100 Subject: [PATCH 157/247] optimize: do not emit useless AND instructions BAND8 was emitting useles AND8 routine. Fixed. --- arch/zx48k/backend/__8bit.py | 1 - tests/functional/band8.asm | 14 -------------- tests/functional/bitwise.asm | 14 -------------- tests/functional/opt3_lcd5.asm | 20 +++----------------- 4 files changed, 3 insertions(+), 46 deletions(-) diff --git a/arch/zx48k/backend/__8bit.py b/arch/zx48k/backend/__8bit.py index 625794830..316bcbe46 100644 --- a/arch/zx48k/backend/__8bit.py +++ b/arch/zx48k/backend/__8bit.py @@ -787,7 +787,6 @@ def _band8(ins): output = _8bit_oper(op1, op2) output.append('and h') output.append('push af') - REQUIRES.add('and8.asm') return output diff --git a/tests/functional/band8.asm b/tests/functional/band8.asm index 0f5061301..546a9f035 100644 --- a/tests/functional/band8.asm +++ b/tests/functional/band8.asm @@ -54,20 +54,6 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 -#line 1 "and8.asm" - - ; FASTCALL boolean and 8 version. - ; result in Accumulator (0 False, not 0 True) -; __FASTCALL__ version (operands: A, H) - ; Performs 8bit and 8bit and returns the boolean - -__AND8: - or a - ret z - ld a, h - ret - -#line 46 "band8.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/bitwise.asm b/tests/functional/bitwise.asm index 18ea78b7e..dbaee72ca 100644 --- a/tests/functional/bitwise.asm +++ b/tests/functional/bitwise.asm @@ -41,20 +41,6 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 -#line 1 "and8.asm" - - ; FASTCALL boolean and 8 version. - ; result in Accumulator (0 False, not 0 True) -; __FASTCALL__ version (operands: A, H) - ; Performs 8bit and 8bit and returns the boolean - -__AND8: - or a - ret z - ld a, h - ret - -#line 33 "bitwise.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/opt3_lcd5.asm b/tests/functional/opt3_lcd5.asm index 7e643c63c..06e2b8323 100644 --- a/tests/functional/opt3_lcd5.asm +++ b/tests/functional/opt3_lcd5.asm @@ -378,20 +378,6 @@ _ScanNear__leave: ex (sp), hl exx ret -#line 1 "and8.asm" - - ; FASTCALL boolean and 8 version. - ; result in Accumulator (0 False, not 0 True) -; __FASTCALL__ version (operands: A, H) - ; Performs 8bit and 8bit and returns the boolean - -__AND8: - or a - ret z - ld a, h - ret - -#line 370 "opt3_lcd5.bas" #line 1 "ftou32reg.asm" #line 1 "neg32.asm" @@ -502,7 +488,7 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A ld a, l ret -#line 371 "opt3_lcd5.bas" +#line 370 "opt3_lcd5.bas" #line 1 "lei16.asm" __LEI16: @@ -521,7 +507,7 @@ checkParity: inc a ; True ret ENDP -#line 372 "opt3_lcd5.bas" +#line 371 "opt3_lcd5.bas" #line 1 "lti16.asm" #line 1 "lei8.asm" @@ -564,7 +550,7 @@ checkParity: inc a ; True ret ENDP -#line 373 "opt3_lcd5.bas" +#line 372 "opt3_lcd5.bas" ZXBASIC_USER_DATA: _x: From c9640b0212a4ca65ad9da54e086f54d4e3285b42 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 30 Jan 2018 22:58:09 +0100 Subject: [PATCH 158/247] bugfix: crash in ASM on JR Z, When using a jump instruction with a non existant label, the assembler might crash after reporting the error. Fixed. --- asmparse.py | 3 +++ tests/functional/jr_no_label.asm | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 tests/functional/jr_no_label.asm diff --git a/asmparse.py b/asmparse.py index 3d291db62..54a13883f 100755 --- a/asmparse.py +++ b/asmparse.py @@ -165,6 +165,9 @@ def argval(self): return tuple([x.eval() if isinstance(x, Expr) else x for x in self.arg]) self.arg = tuple([x if not isinstance(x, Expr) else x.eval() for x in self.arg]) + if gl.has_errors: + return [None] + if self.asm.split(' ')[0] in ('JR', 'DJNZ'): # A relative jump? if self.arg[0] < -128 or self.arg[0] > 127: error(self.lineno, 'Relative jump out of range') diff --git a/tests/functional/jr_no_label.asm b/tests/functional/jr_no_label.asm new file mode 100644 index 000000000..b183aff49 --- /dev/null +++ b/tests/functional/jr_no_label.asm @@ -0,0 +1,2 @@ + jr z,sigPuente + From 20d655b6d5739dd9efaf76e6dea3130ced804c49 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 3 Feb 2018 21:11:07 +0100 Subject: [PATCH 159/247] bugfix: prevent crash when using zxblex alone The module zxblex.py was crashing if run alone. Fixed. --- zxblex.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zxblex.py b/zxblex.py index ac8235dfc..790ce30ac 100755 --- a/zxblex.py +++ b/zxblex.py @@ -502,7 +502,7 @@ def t_ID(t): if t.type != 'ID': t.value = t.type else: - entry = api.global_.SYMBOL_TABLE.get_entry(t.value) + entry = api.global_.SYMBOL_TABLE.get_entry(t.value) if api.global_.SYMBOL_TABLE is not None else None if entry: t.type = callables.get(entry.class_, t.type) From 1e091d5c1f42601c2c4cf14a20f22377f578a85d Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 2 Feb 2018 23:13:03 +0100 Subject: [PATCH 160/247] story: add support for EndIF EndIF (or EndIf or the whatever) is now allowed. --- keywords.py | 1 + tests/functional/endif.asm | 45 ++++++++++++++++++++++++++++++++++++++ tests/functional/endif.bas | 7 ++++++ zxbparser.py | 4 +++- 4 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 tests/functional/endif.asm create mode 100644 tests/functional/endif.bas diff --git a/keywords.py b/keywords.py index f4ecdcf6a..02fcc8d53 100755 --- a/keywords.py +++ b/keywords.py @@ -50,6 +50,7 @@ 'else': 'ELSE', 'elseif': 'ELSEIF', 'end': 'END', + 'endif': 'ENDIF', 'error': 'ERROR', 'exit': 'EXIT', 'exp': 'EXP', diff --git a/tests/functional/endif.asm b/tests/functional/endif.asm new file mode 100644 index 000000000..23c038c6d --- /dev/null +++ b/tests/functional/endif.asm @@ -0,0 +1,45 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld h, 0 + ld a, (_a) + cp h + jp nc, __LABEL1 + ld a, (_a) + inc a + ld (_a), a +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/endif.bas b/tests/functional/endif.bas new file mode 100644 index 000000000..2c74e2524 --- /dev/null +++ b/tests/functional/endif.bas @@ -0,0 +1,7 @@ + +DIM a as UByte + +IF a < 0 THEN + a = a + 1 +ENDIF + diff --git a/zxbparser.py b/zxbparser.py index 16d0cbaf7..abbc40279 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -1187,8 +1187,10 @@ def p_if_sentence(p): def p_endif(p): """ endif : END IF | LABEL END IF + | ENDIF + | LABEL ENDIF """ - p[0] = make_nop() if p[1] == 'END' else make_label(p[1], p.lineno(1)) + p[0] = make_nop() if p[1] in ('END', 'ENDIF') else make_label(p[1], p.lineno(1)) def p_statement_if(p): From 25d1cd4eaf082408e209f074ad2d440c6e33fbdb Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 3 Feb 2018 21:11:28 +0100 Subject: [PATCH 161/247] story: allow BIN with no number BIN alone (not followed by [01]+) should be interpreted as BIN 0 --- tests/functional/bin01.asm | 39 ++++++++++++++++++++++++++++++++++++ tests/functional/bin01.bas | 3 +++ tests/functional/bin02.bas | 2 ++ tests/functional/bin03.asm | 41 ++++++++++++++++++++++++++++++++++++++ tests/functional/bin03.bas | 2 ++ zxblex.py | 21 +++++++++++++------ 6 files changed, 102 insertions(+), 6 deletions(-) create mode 100644 tests/functional/bin01.asm create mode 100644 tests/functional/bin01.bas create mode 100644 tests/functional/bin02.bas create mode 100644 tests/functional/bin03.asm create mode 100644 tests/functional/bin03.bas diff --git a/tests/functional/bin01.asm b/tests/functional/bin01.asm new file mode 100644 index 000000000..c708b31ab --- /dev/null +++ b/tests/functional/bin01.asm @@ -0,0 +1,39 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + xor a + ld (_a), a + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/bin01.bas b/tests/functional/bin01.bas new file mode 100644 index 000000000..ccde327e2 --- /dev/null +++ b/tests/functional/bin01.bas @@ -0,0 +1,3 @@ +REM BIN (alone) is like BIN 0 +LET a = BIN + diff --git a/tests/functional/bin02.bas b/tests/functional/bin02.bas new file mode 100644 index 000000000..3447ea666 --- /dev/null +++ b/tests/functional/bin02.bas @@ -0,0 +1,2 @@ + +LET a = BIN a = a + 1 diff --git a/tests/functional/bin03.asm b/tests/functional/bin03.asm new file mode 100644 index 000000000..50237cf7b --- /dev/null +++ b/tests/functional/bin03.asm @@ -0,0 +1,41 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + xor a + ld (_a), a + inc a + ld (_a), a + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/bin03.bas b/tests/functional/bin03.bas new file mode 100644 index 000000000..ff2a79875 --- /dev/null +++ b/tests/functional/bin03.bas @@ -0,0 +1,2 @@ + +LET a = BIN: a = a + 1 diff --git a/zxblex.py b/zxblex.py index 790ce30ac..51be26582 100755 --- a/zxblex.py +++ b/zxblex.py @@ -583,6 +583,21 @@ def t_INITIAL_bin_LineContinue(t): LABELS_ALLOWED = False +# Separator skipped +def t_INITIAL_bin_preproc_SEPARATOR(t): + r'[ \t]+' + pass + + +def t_bin_ZERO(t): + r'[^01]' + t.lexer.begin('INITIAL') + t.type = 'NUMBER' + t.value = 0 + t.lexer.lexpos -= 1 + return t + + # track line numbers def t_INITIAL_bin_NEWLINE(t): r'\r?\n' @@ -594,12 +609,6 @@ def t_INITIAL_bin_NEWLINE(t): return t -# Separator skipped -def t_INITIAL_bin_preproc_SEPARATOR(t): - r'[ \t]+' - pass - - def t_INITIAL_bin_string_asm_preproc_comment_ERROR(t): r'.' syntax_error(t.lineno, "ignoring illegal character '%s'" % t.value[0]) From 1a600024fa8bd96ac516b953bdc54540ee72e165 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 3 Feb 2018 21:32:20 +0100 Subject: [PATCH 162/247] bugfix: crash upon invalid lexer chars Seems the _error function captures the invalid lexical char but raises an exception afterwards. So let's add a _ERROR function that handles invalid chars (as done in zxblex.py). Fixed. --- asmlex.py | 17 ++++++++++------- tests/functional/asmerror2.asm | 3 +++ tests/functional/test_errmsg.txt | 4 +++- 3 files changed, 16 insertions(+), 8 deletions(-) create mode 100644 tests/functional/asmerror2.asm diff --git a/asmlex.py b/asmlex.py index f53fdea3b..87ccdf8a7 100755 --- a/asmlex.py +++ b/asmlex.py @@ -355,11 +355,6 @@ def t_INITIAL_preproc_STRING(self, t): t.value = t.value[1:-1].replace('""', '"') # Remove quotes return t - def t_INITIAL_preproc_error(self, t): - """ error handling rule - """ - syntax_error(t.lexer.lineno, "illegal character '%s'" % t.value[0]) - def t_INITIAL_preproc_CONTINUE(self, t): r'\\\r?\n' t.lexer.lineno += 1 @@ -371,7 +366,6 @@ def t_COMMENT(self, t): def t_INITIAL_preproc_NEWLINE(self, t): r'\r?\n' - t.lexer.lineno += 1 t.lexer.begin('INITIAL') return t @@ -382,7 +376,16 @@ def t_INITIAL_SHARP(self, t): if self.find_column(t) == 1: t.lexer.begin('preproc') else: - syntax_error(t.lexer.lineno, "illegal character '%s'" % t.value[0]) + self.t_INITIAL_preproc_error(t) + + def t_INITIAL_preproc_ERROR(self, t): + r'.' + self.t_INITIAL_preproc_error(t) + + def t_INITIAL_preproc_error(self, t): + # error handling rule + syntax_error(t.lexer.lineno, "illegal character '%s'" % t.value[0]) + def __init__(self): """ Creates a new GLOBAL lexer instance diff --git a/tests/functional/asmerror2.asm b/tests/functional/asmerror2.asm new file mode 100644 index 000000000..b21ffbc04 --- /dev/null +++ b/tests/functional/asmerror2.asm @@ -0,0 +1,3 @@ + + LD a, @# + diff --git a/tests/functional/test_errmsg.txt b/tests/functional/test_errmsg.txt index 00e02bbb8..36c765331 100644 --- a/tests/functional/test_errmsg.txt +++ b/tests/functional/test_errmsg.txt @@ -110,4 +110,6 @@ fornextopt.bas:4: warning: FOR start value is greater than end. This FOR loop is fornextopt2.bas:4: warning: FOR start value is lower than end. This FOR loop is useless >>> process_file('atoloduplbl.asm') atoloduplbl.asm:3: label '.SetSubScreen' already defined at line 2 - +>>> process_file('asmerror2.asm') +asmerror2.asm:2: Error: illegal preprocessor character '@' +asmerror2.asm:2: Syntax error. Unexpected end of line [NEWLINE] From c84214cfa6db427f7778100d2571dbc08a543f4f Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 4 Feb 2018 10:49:55 +0100 Subject: [PATCH 163/247] story: allow spaces before ':' in asm labels This way label: and label : are allowed and equivalent --- asmlex.py | 10 +++++++--- tests/functional/asmlabel1.asm | 4 ++++ tests/functional/asmlabel1.bin | Bin 0 -> 3 bytes 3 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 tests/functional/asmlabel1.asm create mode 100644 tests/functional/asmlabel1.bin diff --git a/asmlex.py b/asmlex.py index 87ccdf8a7..514b6dc0d 100755 --- a/asmlex.py +++ b/asmlex.py @@ -16,7 +16,7 @@ from api.config import OPTIONS from api.errmsg import syntax_error -_tokens = ('STRING', 'NEWLINE', 'LABEL', +_tokens = ('STRING', 'NEWLINE', 'LABEL', 'CO', 'ID', 'COMMA', 'PLUS', 'MINUS', 'LP', 'RP', 'LPP', 'RPP', 'MUL', 'DIV', 'POW', 'MOD', 'UMINUS', 'APO', 'INTEGER', 'ADDR', 'LSHIFT', 'RSHIFT', 'BAND', 'BOR', 'BXOR' @@ -244,12 +244,12 @@ def t_INITIAL_preproc_INTEGER(self, t): return t def t_INITIAL_ID(self, t): - r'[._a-zA-Z]([._a-zA-Z0-9]+)*[:]?' # Any identifier + r'[._a-zA-Z][._a-zA-Z0-9]*([ \t]*[:])?' # Any identifier tmp = t.value # Saves original value if tmp[-1] == ':': t.type = 'LABEL' - t.value = tmp[:-1] + t.value = tmp[:-1].strip() return t t.value = tmp.upper() # Convert it to uppercase, since our internal tables uses uppercase @@ -350,6 +350,10 @@ def t_APO(self, t): r"'" return t + def t_CO(self, t): + r":" + return t + def t_INITIAL_preproc_STRING(self, t): r'"(""|[^"])*"' # a doubled quoted string t.value = t.value[1:-1].replace('""', '"') # Remove quotes diff --git a/tests/functional/asmlabel1.asm b/tests/functional/asmlabel1.asm new file mode 100644 index 000000000..f7c2fccee --- /dev/null +++ b/tests/functional/asmlabel1.asm @@ -0,0 +1,4 @@ + +label : + jp label + diff --git a/tests/functional/asmlabel1.bin b/tests/functional/asmlabel1.bin new file mode 100644 index 0000000000000000000000000000000000000000..894ac62eabeef64bd0df6584e3f783df72e333e0 GIT binary patch literal 3 KcmX@izyJUOOaR0H literal 0 HcmV?d00001 From c9d7a4a3ea07d98ebfcedb99a36980b2f36f84b1 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 4 Feb 2018 11:05:53 +0100 Subject: [PATCH 164/247] cleanup: remove blank lines --- asmparse.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/asmparse.py b/asmparse.py index 54a13883f..8f8eb75e8 100755 --- a/asmparse.py +++ b/asmparse.py @@ -618,7 +618,6 @@ def p_def_label(p): """ p[0] = None __DEBUG__("Declaring '%s%s' in %i" % (NAMESPACE, p[1], p.lineno(1))) - MEMORY.declare_label(p[1], p.lineno(1), p[3]) @@ -627,7 +626,6 @@ def p_line_label(p): """ p[0] = None # Nothing to append __DEBUG__("Declaring '%s%s' (value %04Xh) in %i" % (NAMESPACE, p[1], MEMORY.org, p.lineno(1))) - MEMORY.declare_label(p[1], p.lineno(1)) @@ -636,7 +634,6 @@ def p_line_label_asm(p): """ p[0] = p[2] __DEBUG__("Declaring '%s' (value %04Xh) in %i" % (p[1], MEMORY.org, p.lineno(1))) - MEMORY.declare_label(p[1], p.lineno(1)) From bf57f30864dc58aa0c45b95def1fa356e719bba3 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 4 Feb 2018 11:06:17 +0100 Subject: [PATCH 165/247] refact: asm is also a label followed by an inst --- asmparse.py | 2 +- tests/functional/asmlabel2.asm | 5 +++++ tests/functional/asmlabel2.bin | Bin 0 -> 3 bytes 3 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 tests/functional/asmlabel2.asm create mode 100644 tests/functional/asmlabel2.bin diff --git a/asmparse.py b/asmparse.py index 8f8eb75e8..4374473ac 100755 --- a/asmparse.py +++ b/asmparse.py @@ -630,7 +630,7 @@ def p_line_label(p): def p_line_label_asm(p): - """ line : LABEL asm NEWLINE + """ asm : LABEL asm NEWLINE """ p[0] = p[2] __DEBUG__("Declaring '%s' (value %04Xh) in %i" % (p[1], MEMORY.org, p.lineno(1))) diff --git a/tests/functional/asmlabel2.asm b/tests/functional/asmlabel2.asm new file mode 100644 index 000000000..3d90bd111 --- /dev/null +++ b/tests/functional/asmlabel2.asm @@ -0,0 +1,5 @@ + +; test label: instruction + +test: jp test + diff --git a/tests/functional/asmlabel2.bin b/tests/functional/asmlabel2.bin new file mode 100644 index 0000000000000000000000000000000000000000..894ac62eabeef64bd0df6584e3f783df72e333e0 GIT binary patch literal 3 KcmX@izyJUOOaR0H literal 0 HcmV?d00001 From fb7f9e455074effd5ccc69625e723272c717f806 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 4 Feb 2018 11:50:14 +0100 Subject: [PATCH 166/247] story: allow multiple inst in a one line For example: ld a, 1: ld b, 2 is now allowed --- asmlex.py | 1 - asmparse.py | 50 ++++++++++++++++++---------------- tests/functional/asmcolon.asm | 9 ++++++ tests/functional/asmcolon.bin | Bin 0 -> 15 bytes tests/functional/newl.asm | 4 +++ zxbasm.py | 2 +- 6 files changed, 41 insertions(+), 25 deletions(-) create mode 100644 tests/functional/asmcolon.asm create mode 100644 tests/functional/asmcolon.bin create mode 100644 tests/functional/newl.asm diff --git a/asmlex.py b/asmlex.py index 514b6dc0d..f50c65c49 100755 --- a/asmlex.py +++ b/asmlex.py @@ -390,7 +390,6 @@ def t_INITIAL_preproc_error(self, t): # error handling rule syntax_error(t.lexer.lineno, "illegal character '%s'" % t.value[0]) - def __init__(self): """ Creates a new GLOBAL lexer instance """ diff --git a/asmparse.py b/asmparse.py index 4374473ac..21f538a0d 100755 --- a/asmparse.py +++ b/asmparse.py @@ -449,7 +449,7 @@ def set_memory_slot(self): self.orgs[self.org] = () # Declares an empty memory slot if not already done self.memory_bytes[self.org] = () # Declares an empty memory slot if not already done - def add_instruction(self, asm): + def add_instruction(self, instr): """ This will insert an asm instruction at the current memory position in a t-uple as (mnemonic, params). @@ -458,11 +458,12 @@ def add_instruction(self, asm): if gl.has_errors: return + __DEBUG__('%04Xh [%04Xh] ASM: %s' % (self.org, self.org - self.ORG, instr.asm)) self.set_memory_slot() - self.orgs[self.org] += (asm,) + self.orgs[self.org] += (instr,) - for byte in asm.bytes(): - self.__set_byte(byte, asm.lineno) + for byte in instr.bytes(): + self.__set_byte(byte, instr.lineno) def dump(self): """ Returns a tuple containing code ORG, and a list of OUTPUT @@ -600,16 +601,14 @@ def p_program(p): """ program : line """ if p[1] is not None: - __DEBUG__('%04Xh [%04Xh] ASM: %s' % (MEMORY.org, MEMORY.org - MEMORY.ORG, p[1].asm)) - MEMORY.add_instruction(p[1]) + [MEMORY.add_instruction(x) for x in p[1] if isinstance(x, Asm)] def p_program_line(p): """ program : program line """ if p[2] is not None: - __DEBUG__('%04Xh [%04Xh] ASM: %s' % (MEMORY.org, MEMORY.org - MEMORY.ORG, p[2].asm)) - MEMORY.add_instruction(p[2]) + [MEMORY.add_instruction(x) for x in p[2] if isinstance(x, Asm)] def p_def_label(p): @@ -621,32 +620,37 @@ def p_def_label(p): MEMORY.declare_label(p[1], p.lineno(1), p[3]) -def p_line_label(p): - """ line : LABEL NEWLINE - """ - p[0] = None # Nothing to append - __DEBUG__("Declaring '%s%s' (value %04Xh) in %i" % (NAMESPACE, p[1], MEMORY.org, p.lineno(1))) - MEMORY.declare_label(p[1], p.lineno(1)) - - def p_line_label_asm(p): - """ asm : LABEL asm NEWLINE + """ line : LABEL asms NEWLINE """ p[0] = p[2] - __DEBUG__("Declaring '%s' (value %04Xh) in %i" % (p[1], MEMORY.org, p.lineno(1))) + __DEBUG__("Declaring '%s%s' (value %04Xh) in %i" % (NAMESPACE, p[1], MEMORY.org, p.lineno(1))) MEMORY.declare_label(p[1], p.lineno(1)) def p_line_asm(p): - """ line : asm NEWLINE + """ line : asms NEWLINE """ p[0] = p[1] -def p_line_newline(p): - """ line : NEWLINE +def p_asms_empty(p): + """ asms : """ - p[0] = None + p[0] = [] + + +def p_asms_asm(p): + """ asms : asm + """ + p[0] = [p[1]] + + +def p_asms_asms_asm(p): + """ asms : asms CO asm + """ + p[1].append(p[3]) + p[0] = p[1] def p_asm_ld8(p): @@ -1381,7 +1385,7 @@ def p_expr_addr(p): # Some preprocessor directives def p_preprocessor_line(p): - """ asm : preproc_line + """ line : preproc_line """ p[0] = None diff --git a/tests/functional/asmcolon.asm b/tests/functional/asmcolon.asm new file mode 100644 index 000000000..963759f94 --- /dev/null +++ b/tests/functional/asmcolon.asm @@ -0,0 +1,9 @@ + + LD a, 5 + LD b, 1 + + LD a, 5: LD b, 1 + +TEST: LD a, 5: LD b, 1 + jp TEST + diff --git a/tests/functional/asmcolon.bin b/tests/functional/asmcolon.bin new file mode 100644 index 0000000000000000000000000000000000000000..24a5c979f529f718caeb8c396e1a196abb3a5053 GIT binary patch literal 15 QcmcCxWn;91;=>#a01LJOssI20 literal 0 HcmV?d00001 diff --git a/tests/functional/newl.asm b/tests/functional/newl.asm new file mode 100644 index 000000000..fd40910d9 --- /dev/null +++ b/tests/functional/newl.asm @@ -0,0 +1,4 @@ + + + + diff --git a/zxbasm.py b/zxbasm.py index 38f0b3d0e..be4a999de 100755 --- a/zxbasm.py +++ b/zxbasm.py @@ -24,7 +24,7 @@ from api import global_ # Release version -VERSION = '1.10' +VERSION = '1.11' def main(args=None): From 86271b1389c93b3df6b254a45091c87b824adf71 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 6 Feb 2018 23:38:28 +0100 Subject: [PATCH 167/247] bugfix: fix a wrong token code for LET --- basic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basic.py b/basic.py index 97f68ba98..2b801c5d5 100755 --- a/basic.py +++ b/basic.py @@ -29,7 +29,7 @@ 'CLS': 251, 'CLEAR': 253, 'PAUSE': 242, - 'LET': 231, + 'LET': 241, 'INPUT': 238, 'READ': 227, 'DATA': 228, From 14020c89dce3b241949e2a7d467c67f183b838b3 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 6 Feb 2018 00:37:17 +0100 Subject: [PATCH 168/247] add C Nonsense in BASIC error code --- library-asm/error.asm | 1 + tests/functional/27.asm | 1 + tests/functional/28.asm | 1 + tests/functional/29.asm | 1 + tests/functional/48.asm | 1 + tests/functional/49.asm | 1 + tests/functional/addstr.asm | 1 + tests/functional/aloadstr0.asm | 1 + tests/functional/aloadstr1.asm | 1 + tests/functional/arden2.asm | 1 + tests/functional/array07.asm | 1 + tests/functional/array08.asm | 1 + tests/functional/array09.asm | 1 + tests/functional/array12.asm | 1 + tests/functional/astore16.asm | 1 + tests/functional/break.asm | 1 + tests/functional/chr.asm | 1 + tests/functional/chr0.asm | 1 + tests/functional/chr1.asm | 1 + tests/functional/circle.asm | 1 + tests/functional/code00.asm | 1 + tests/functional/code01.asm | 1 + tests/functional/code02.asm | 1 + tests/functional/codecrash2.asm | 1 + tests/functional/codecrash3.asm | 1 + tests/functional/codecrash4.asm | 1 + tests/functional/coercion1.asm | 1 + tests/functional/divf00.asm | 1 + tests/functional/divf01.asm | 1 + tests/functional/draw.asm | 1 + tests/functional/draw3.asm | 1 + tests/functional/einarattr.asm | 1 + tests/functional/einarshift.asm | 1 + tests/functional/emptystrparam.asm | 1 + tests/functional/fact.asm | 1 + tests/functional/fastcall0.asm | 1 + tests/functional/for0.asm | 1 + tests/functional/ifelse1.asm | 1 + tests/functional/ifwhilex.asm | 1 + tests/functional/inkey.asm | 1 + tests/functional/inktemp.asm | 1 + tests/functional/lcd3.asm | 1 + tests/functional/lcd7.asm | 1 + tests/functional/lcd8.asm | 1 + tests/functional/lcd9.asm | 1 + tests/functional/load02.asm | 1 + tests/functional/load03.asm | 1 + tests/functional/loadstr.asm | 1 + tests/functional/loadu16ii.asm | 1 + tests/functional/ltee1.asm | 1 + tests/functional/ltee3.asm | 1 + tests/functional/ltee5.asm | 1 + tests/functional/ltee6.asm | 1 + tests/functional/ltee7.asm | 1 + tests/functional/mcleod2.asm | 1 + tests/functional/memcpytest.asm | 1 + tests/functional/ongoto.asm | 1 + tests/functional/opt2_pstr.asm | 1 + tests/functional/opt3_data2.asm | 1 + tests/functional/opt3_einar.asm | 1 + tests/functional/optconst.asm | 1 + tests/functional/param0.asm | 1 + tests/functional/param1.asm | 1 + tests/functional/param2.asm | 1 + tests/functional/parambyref1.asm | 1 + tests/functional/paramstr3.asm | 1 + tests/functional/paramstr4.asm | 1 + tests/functional/paramstr5.asm | 1 + tests/functional/plot.asm | 1 + tests/functional/print.asm | 1 + tests/functional/print42.asm | 8 ++++---- tests/functional/print64.asm | 8 ++++---- tests/functional/read.asm | 1 + tests/functional/read10.asm | 1 + tests/functional/read12.asm | 1 + tests/functional/read4.asm | 1 + tests/functional/read5.asm | 1 + tests/functional/read8.asm | 1 + tests/functional/read9.asm | 1 + tests/functional/readokdown.asm | 1 + tests/functional/readokup.asm | 1 + tests/functional/save01.asm | 1 + tests/functional/save02.asm | 1 + tests/functional/save03.asm | 1 + tests/functional/sigilfunc.asm | 1 + tests/functional/simple.asm | 1 + tests/functional/slice0.asm | 1 + tests/functional/slice2.asm | 1 + tests/functional/spfill.asm | 1 + tests/functional/stoperr.asm | 1 + tests/functional/storecstr.asm | 1 + tests/functional/storestr0.asm | 1 + tests/functional/storestr1.asm | 1 + tests/functional/storestr2.asm | 1 + tests/functional/str0.asm | 1 + tests/functional/str00.asm | 1 + tests/functional/str01.asm | 1 + tests/functional/str02.asm | 1 + tests/functional/stradd.asm | 1 + tests/functional/strbase.asm | 1 + tests/functional/strbase2.asm | 1 + tests/functional/stringfunc.asm | 1 + tests/functional/stringparam.asm | 1 + tests/functional/strlocal0.asm | 1 + tests/functional/strparam0.asm | 1 + tests/functional/strparam1.asm | 1 + tests/functional/strparam2.asm | 1 + tests/functional/strparam3.asm | 1 + tests/functional/strsigil.asm | 1 + tests/functional/subrec.asm | 1 + tests/functional/substrlval.asm | 1 + tests/functional/usr0.asm | 1 + tests/functional/valcrash2.asm | 1 + 113 files changed, 119 insertions(+), 8 deletions(-) diff --git a/library-asm/error.asm b/library-asm/error.asm index 153ecabb8..952cac736 100644 --- a/library-asm/error.asm +++ b/library-asm/error.asm @@ -18,6 +18,7 @@ ERROR_OutOfScreen EQU 4 ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 +ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/27.asm b/tests/functional/27.asm index 21af47d39..d2a9b4ce9 100644 --- a/tests/functional/27.asm +++ b/tests/functional/27.asm @@ -149,6 +149,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/28.asm b/tests/functional/28.asm index 4c6be573c..178f0e491 100644 --- a/tests/functional/28.asm +++ b/tests/functional/28.asm @@ -152,6 +152,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/29.asm b/tests/functional/29.asm index 83214e146..28215e290 100644 --- a/tests/functional/29.asm +++ b/tests/functional/29.asm @@ -141,6 +141,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/48.asm b/tests/functional/48.asm index c7b6b2d1a..1c6daa6c1 100644 --- a/tests/functional/48.asm +++ b/tests/functional/48.asm @@ -160,6 +160,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/49.asm b/tests/functional/49.asm index aeca6373d..42a6b4f04 100644 --- a/tests/functional/49.asm +++ b/tests/functional/49.asm @@ -160,6 +160,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/addstr.asm b/tests/functional/addstr.asm index a12c7827e..34c350ca2 100644 --- a/tests/functional/addstr.asm +++ b/tests/functional/addstr.asm @@ -517,6 +517,7 @@ __STORE_STR2: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/aloadstr0.asm b/tests/functional/aloadstr0.asm index f0804dcb7..46a9d5c02 100644 --- a/tests/functional/aloadstr0.asm +++ b/tests/functional/aloadstr0.asm @@ -127,6 +127,7 @@ __CALL_BACK__: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/aloadstr1.asm b/tests/functional/aloadstr1.asm index 6cf9729cc..9507c722b 100644 --- a/tests/functional/aloadstr1.asm +++ b/tests/functional/aloadstr1.asm @@ -335,6 +335,7 @@ __FNMUL2: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/arden2.asm b/tests/functional/arden2.asm index d64ad7bb3..7cce41a1c 100644 --- a/tests/functional/arden2.asm +++ b/tests/functional/arden2.asm @@ -135,6 +135,7 @@ __CALL_BACK__: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/array07.asm b/tests/functional/array07.asm index 67710ccdb..d8aeb3612 100644 --- a/tests/functional/array07.asm +++ b/tests/functional/array07.asm @@ -687,6 +687,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/array08.asm b/tests/functional/array08.asm index 264cc06f7..11d22cf91 100644 --- a/tests/functional/array08.asm +++ b/tests/functional/array08.asm @@ -346,6 +346,7 @@ __FNMUL2: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/array09.asm b/tests/functional/array09.asm index a75bd3841..778c07563 100644 --- a/tests/functional/array09.asm +++ b/tests/functional/array09.asm @@ -346,6 +346,7 @@ __FNMUL2: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/array12.asm b/tests/functional/array12.asm index dd0225383..70da58a5f 100644 --- a/tests/functional/array12.asm +++ b/tests/functional/array12.asm @@ -348,6 +348,7 @@ __FNMUL2: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/astore16.asm b/tests/functional/astore16.asm index 85e4f0621..5d9a483d6 100644 --- a/tests/functional/astore16.asm +++ b/tests/functional/astore16.asm @@ -380,6 +380,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/break.asm b/tests/functional/break.asm index 3da3dfcfd..5d518b278 100644 --- a/tests/functional/break.asm +++ b/tests/functional/break.asm @@ -81,6 +81,7 @@ __CALL_BACK__: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/chr.asm b/tests/functional/chr.asm index f519ef983..8d3a16584 100644 --- a/tests/functional/chr.asm +++ b/tests/functional/chr.asm @@ -139,6 +139,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/chr0.asm b/tests/functional/chr0.asm index f9da653ba..6dac9c5e8 100644 --- a/tests/functional/chr0.asm +++ b/tests/functional/chr0.asm @@ -138,6 +138,7 @@ __CALL_BACK__: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/chr1.asm b/tests/functional/chr1.asm index 46ab1fa00..9f3ca5b64 100644 --- a/tests/functional/chr1.asm +++ b/tests/functional/chr1.asm @@ -145,6 +145,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/circle.asm b/tests/functional/circle.asm index 04eb3df30..6c709a2f9 100644 --- a/tests/functional/circle.asm +++ b/tests/functional/circle.asm @@ -111,6 +111,7 @@ __CALL_BACK__: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/code00.asm b/tests/functional/code00.asm index 59cd0b007..805c41046 100644 --- a/tests/functional/code00.asm +++ b/tests/functional/code00.asm @@ -135,6 +135,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/code01.asm b/tests/functional/code01.asm index d5bbec89e..0fccfcb58 100644 --- a/tests/functional/code01.asm +++ b/tests/functional/code01.asm @@ -135,6 +135,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/code02.asm b/tests/functional/code02.asm index f748f23ed..d42f63f8f 100644 --- a/tests/functional/code02.asm +++ b/tests/functional/code02.asm @@ -135,6 +135,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/codecrash2.asm b/tests/functional/codecrash2.asm index 62f693d81..3114dcf54 100644 --- a/tests/functional/codecrash2.asm +++ b/tests/functional/codecrash2.asm @@ -484,6 +484,7 @@ __ASC_END: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/codecrash3.asm b/tests/functional/codecrash3.asm index aa4eacfec..e70a29837 100644 --- a/tests/functional/codecrash3.asm +++ b/tests/functional/codecrash3.asm @@ -487,6 +487,7 @@ __ASC_END: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/codecrash4.asm b/tests/functional/codecrash4.asm index 485df0f9c..1778fa842 100644 --- a/tests/functional/codecrash4.asm +++ b/tests/functional/codecrash4.asm @@ -497,6 +497,7 @@ __ASC_END: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/coercion1.asm b/tests/functional/coercion1.asm index 37983f6b3..ba98b26ce 100644 --- a/tests/functional/coercion1.asm +++ b/tests/functional/coercion1.asm @@ -173,6 +173,7 @@ __ADDF: ; Addition ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/divf00.asm b/tests/functional/divf00.asm index 4ca99a357..16e912b89 100644 --- a/tests/functional/divf00.asm +++ b/tests/functional/divf00.asm @@ -106,6 +106,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/divf01.asm b/tests/functional/divf01.asm index af31893ed..f65528a7b 100644 --- a/tests/functional/divf01.asm +++ b/tests/functional/divf01.asm @@ -110,6 +110,7 @@ __FPSTACK_I16: ; Pushes 16 bits integer in HL into the FP ROM STACK ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/draw.asm b/tests/functional/draw.asm index f489f59fa..eb0e923eb 100644 --- a/tests/functional/draw.asm +++ b/tests/functional/draw.asm @@ -85,6 +85,7 @@ __CALL_BACK__: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/draw3.asm b/tests/functional/draw3.asm index e10f28473..e142351cb 100644 --- a/tests/functional/draw3.asm +++ b/tests/functional/draw3.asm @@ -117,6 +117,7 @@ __CALL_BACK__: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/einarattr.asm b/tests/functional/einarattr.asm index 1fe316dcd..abc4773f7 100644 --- a/tests/functional/einarattr.asm +++ b/tests/functional/einarattr.asm @@ -174,6 +174,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/einarshift.asm b/tests/functional/einarshift.asm index df937ada5..faf044fee 100644 --- a/tests/functional/einarshift.asm +++ b/tests/functional/einarshift.asm @@ -156,6 +156,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/emptystrparam.asm b/tests/functional/emptystrparam.asm index acc669f63..49cd5e90e 100644 --- a/tests/functional/emptystrparam.asm +++ b/tests/functional/emptystrparam.asm @@ -466,6 +466,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/fact.asm b/tests/functional/fact.asm index d16204a24..aa68f8423 100644 --- a/tests/functional/fact.asm +++ b/tests/functional/fact.asm @@ -332,6 +332,7 @@ __TO32BIT: ; Converts H'L'HLB'C'AC to DEHL (Discards H'L'HL) ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/fastcall0.asm b/tests/functional/fastcall0.asm index e860672a0..ef260a968 100644 --- a/tests/functional/fastcall0.asm +++ b/tests/functional/fastcall0.asm @@ -507,6 +507,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/for0.asm b/tests/functional/for0.asm index 716f0b8c7..289aa31df 100644 --- a/tests/functional/for0.asm +++ b/tests/functional/for0.asm @@ -201,6 +201,7 @@ checkParity: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/ifelse1.asm b/tests/functional/ifelse1.asm index 367eeb448..e9ce4c19f 100644 --- a/tests/functional/ifelse1.asm +++ b/tests/functional/ifelse1.asm @@ -169,6 +169,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/ifwhilex.asm b/tests/functional/ifwhilex.asm index 7bcc9f17b..4c0162001 100644 --- a/tests/functional/ifwhilex.asm +++ b/tests/functional/ifwhilex.asm @@ -189,6 +189,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/inkey.asm b/tests/functional/inkey.asm index 0ba1eb83a..5e7fbeacf 100644 --- a/tests/functional/inkey.asm +++ b/tests/functional/inkey.asm @@ -140,6 +140,7 @@ __CALL_BACK__: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/inktemp.asm b/tests/functional/inktemp.asm index f810689ee..1c537c2ef 100644 --- a/tests/functional/inktemp.asm +++ b/tests/functional/inktemp.asm @@ -78,6 +78,7 @@ __CALL_BACK__: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/lcd3.asm b/tests/functional/lcd3.asm index cd42db1e0..5fbc33539 100644 --- a/tests/functional/lcd3.asm +++ b/tests/functional/lcd3.asm @@ -747,6 +747,7 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/lcd7.asm b/tests/functional/lcd7.asm index 488bec41b..782b3e192 100644 --- a/tests/functional/lcd7.asm +++ b/tests/functional/lcd7.asm @@ -496,6 +496,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/lcd8.asm b/tests/functional/lcd8.asm index 4e7742af2..d1397334c 100644 --- a/tests/functional/lcd8.asm +++ b/tests/functional/lcd8.asm @@ -498,6 +498,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/lcd9.asm b/tests/functional/lcd9.asm index 158aa8ff6..4c609fbaa 100644 --- a/tests/functional/lcd9.asm +++ b/tests/functional/lcd9.asm @@ -486,6 +486,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/load02.asm b/tests/functional/load02.asm index 1f862d854..776974937 100644 --- a/tests/functional/load02.asm +++ b/tests/functional/load02.asm @@ -140,6 +140,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/load03.asm b/tests/functional/load03.asm index 66d9f5cbf..3b1d5afc9 100644 --- a/tests/functional/load03.asm +++ b/tests/functional/load03.asm @@ -139,6 +139,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/loadstr.asm b/tests/functional/loadstr.asm index 15ae45527..2613f8616 100644 --- a/tests/functional/loadstr.asm +++ b/tests/functional/loadstr.asm @@ -151,6 +151,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/loadu16ii.asm b/tests/functional/loadu16ii.asm index fcf7e14bd..9f64911bb 100644 --- a/tests/functional/loadu16ii.asm +++ b/tests/functional/loadu16ii.asm @@ -223,6 +223,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/ltee1.asm b/tests/functional/ltee1.asm index 3ebada3bf..f296066f8 100644 --- a/tests/functional/ltee1.asm +++ b/tests/functional/ltee1.asm @@ -512,6 +512,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/ltee3.asm b/tests/functional/ltee3.asm index 6a60a2631..d5d54226f 100644 --- a/tests/functional/ltee3.asm +++ b/tests/functional/ltee3.asm @@ -474,6 +474,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/ltee5.asm b/tests/functional/ltee5.asm index cc35f44c2..3444c55ff 100644 --- a/tests/functional/ltee5.asm +++ b/tests/functional/ltee5.asm @@ -508,6 +508,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/ltee6.asm b/tests/functional/ltee6.asm index 694c22b10..ef574d011 100644 --- a/tests/functional/ltee6.asm +++ b/tests/functional/ltee6.asm @@ -356,6 +356,7 @@ __FNMUL2: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/ltee7.asm b/tests/functional/ltee7.asm index cab0bbad4..6d0651ee2 100644 --- a/tests/functional/ltee7.asm +++ b/tests/functional/ltee7.asm @@ -784,6 +784,7 @@ __ARRAY_FREE_MEM: ; like the above, buf also frees the array itself ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/mcleod2.asm b/tests/functional/mcleod2.asm index c19bf3ca4..dd0f78606 100644 --- a/tests/functional/mcleod2.asm +++ b/tests/functional/mcleod2.asm @@ -142,6 +142,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/memcpytest.asm b/tests/functional/memcpytest.asm index ca931ade4..d4504a72e 100644 --- a/tests/functional/memcpytest.asm +++ b/tests/functional/memcpytest.asm @@ -295,6 +295,7 @@ __PAUSE: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/ongoto.asm b/tests/functional/ongoto.asm index 5f1bc7b6a..4ce0906ed 100644 --- a/tests/functional/ongoto.asm +++ b/tests/functional/ongoto.asm @@ -288,6 +288,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/opt2_pstr.asm b/tests/functional/opt2_pstr.asm index 56ae8fe80..eb4aa26ec 100644 --- a/tests/functional/opt2_pstr.asm +++ b/tests/functional/opt2_pstr.asm @@ -471,6 +471,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/opt3_data2.asm b/tests/functional/opt3_data2.asm index 8b49f43f7..fb20c2605 100644 --- a/tests/functional/opt3_data2.asm +++ b/tests/functional/opt3_data2.asm @@ -481,6 +481,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/opt3_einar.asm b/tests/functional/opt3_einar.asm index b39f0c2b1..5b26b212b 100644 --- a/tests/functional/opt3_einar.asm +++ b/tests/functional/opt3_einar.asm @@ -180,6 +180,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/optconst.asm b/tests/functional/optconst.asm index 72a7d5426..9eb89c718 100644 --- a/tests/functional/optconst.asm +++ b/tests/functional/optconst.asm @@ -170,6 +170,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/param0.asm b/tests/functional/param0.asm index 4fad8e6c7..4c00c87e2 100644 --- a/tests/functional/param0.asm +++ b/tests/functional/param0.asm @@ -480,6 +480,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/param1.asm b/tests/functional/param1.asm index 7a9b86b67..540d7874b 100644 --- a/tests/functional/param1.asm +++ b/tests/functional/param1.asm @@ -180,6 +180,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/param2.asm b/tests/functional/param2.asm index 20fac6bc1..1016aac03 100644 --- a/tests/functional/param2.asm +++ b/tests/functional/param2.asm @@ -480,6 +480,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/parambyref1.asm b/tests/functional/parambyref1.asm index 6fc2b98b9..0e87ec7ed 100644 --- a/tests/functional/parambyref1.asm +++ b/tests/functional/parambyref1.asm @@ -183,6 +183,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/paramstr3.asm b/tests/functional/paramstr3.asm index d72d2ec1c..6443400fd 100644 --- a/tests/functional/paramstr3.asm +++ b/tests/functional/paramstr3.asm @@ -464,6 +464,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/paramstr4.asm b/tests/functional/paramstr4.asm index d16de88a5..fd58a8f0b 100644 --- a/tests/functional/paramstr4.asm +++ b/tests/functional/paramstr4.asm @@ -488,6 +488,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/paramstr5.asm b/tests/functional/paramstr5.asm index a25a1fe3a..5eb06698b 100644 --- a/tests/functional/paramstr5.asm +++ b/tests/functional/paramstr5.asm @@ -488,6 +488,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/plot.asm b/tests/functional/plot.asm index a8700f670..af14b406c 100644 --- a/tests/functional/plot.asm +++ b/tests/functional/plot.asm @@ -199,6 +199,7 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/print.asm b/tests/functional/print.asm index e7efe354e..809d74e8c 100644 --- a/tests/functional/print.asm +++ b/tests/functional/print.asm @@ -179,6 +179,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/print42.asm b/tests/functional/print42.asm index 110b49251..2416bad1e 100644 --- a/tests/functional/print42.asm +++ b/tests/functional/print42.asm @@ -50,7 +50,7 @@ _print42: push ix ld ix, 0 add ix, sp -#line 23 +#line 21 PROC LD A, H OR L @@ -287,9 +287,9 @@ ycoord: ret c ld d, 0 ret -#line 259 +#line 257 __LABEL__printAt42Coords: -#line 314 +#line 312 LOCAL xycoords xycoords: defb 0 @@ -455,7 +455,7 @@ characters: LOCAL print64end print64end: ENDP -#line 479 +#line 477 _print42__leave: ex af, af' exx diff --git a/tests/functional/print64.asm b/tests/functional/print64.asm index e916b59c2..a0d95b5f7 100644 --- a/tests/functional/print64.asm +++ b/tests/functional/print64.asm @@ -50,7 +50,7 @@ _print64: push ix ld ix, 0 add ix, sp -#line 22 +#line 20 PROC LD L,(IX+4) LD H,(IX+5) @@ -224,9 +224,9 @@ p64_test_Y: ret c ld d, 0 ret -#line 195 +#line 193 __LABEL__p64coords: -#line 224 +#line 222 LOCAL p64_coords p64_coords: defb 64 @@ -284,7 +284,7 @@ p64_charset: LOCAL p64_END p64_END: ENDP -#line 281 +#line 279 _print64__leave: ex af, af' exx diff --git a/tests/functional/read.asm b/tests/functional/read.asm index 3ff97e089..a13c5c1ff 100644 --- a/tests/functional/read.asm +++ b/tests/functional/read.asm @@ -154,6 +154,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/read10.asm b/tests/functional/read10.asm index 774133f6b..ce8409622 100644 --- a/tests/functional/read10.asm +++ b/tests/functional/read10.asm @@ -399,6 +399,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/read12.asm b/tests/functional/read12.asm index 1dd1309d0..1dd151522 100644 --- a/tests/functional/read12.asm +++ b/tests/functional/read12.asm @@ -158,6 +158,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/read4.asm b/tests/functional/read4.asm index d4f6f9e4a..c4c812b36 100644 --- a/tests/functional/read4.asm +++ b/tests/functional/read4.asm @@ -197,6 +197,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/read5.asm b/tests/functional/read5.asm index 875272c60..ca6edd78c 100644 --- a/tests/functional/read5.asm +++ b/tests/functional/read5.asm @@ -346,6 +346,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/read8.asm b/tests/functional/read8.asm index 94be629c2..16c83b7ec 100644 --- a/tests/functional/read8.asm +++ b/tests/functional/read8.asm @@ -337,6 +337,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/read9.asm b/tests/functional/read9.asm index 8a9472b41..3696965e7 100644 --- a/tests/functional/read9.asm +++ b/tests/functional/read9.asm @@ -586,6 +586,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/readokdown.asm b/tests/functional/readokdown.asm index d36b9f358..37686008d 100644 --- a/tests/functional/readokdown.asm +++ b/tests/functional/readokdown.asm @@ -220,6 +220,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/readokup.asm b/tests/functional/readokup.asm index 6b5193922..cf0602341 100644 --- a/tests/functional/readokup.asm +++ b/tests/functional/readokup.asm @@ -219,6 +219,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/save01.asm b/tests/functional/save01.asm index bab7d214f..089346e10 100644 --- a/tests/functional/save01.asm +++ b/tests/functional/save01.asm @@ -140,6 +140,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/save02.asm b/tests/functional/save02.asm index 57f739883..4dd1c6d79 100644 --- a/tests/functional/save02.asm +++ b/tests/functional/save02.asm @@ -137,6 +137,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/save03.asm b/tests/functional/save03.asm index e417a36e1..302a785b7 100644 --- a/tests/functional/save03.asm +++ b/tests/functional/save03.asm @@ -136,6 +136,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/sigilfunc.asm b/tests/functional/sigilfunc.asm index 96e44d8ac..debffd0e0 100644 --- a/tests/functional/sigilfunc.asm +++ b/tests/functional/sigilfunc.asm @@ -138,6 +138,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/simple.asm b/tests/functional/simple.asm index 8622604f1..a7c4850a2 100644 --- a/tests/functional/simple.asm +++ b/tests/functional/simple.asm @@ -162,6 +162,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/slice0.asm b/tests/functional/slice0.asm index 17f562f34..138bb5cdc 100644 --- a/tests/functional/slice0.asm +++ b/tests/functional/slice0.asm @@ -528,6 +528,7 @@ __STRLEN: ; Direct FASTCALL entry ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/slice2.asm b/tests/functional/slice2.asm index d9ecf30c7..cf06faaf7 100644 --- a/tests/functional/slice2.asm +++ b/tests/functional/slice2.asm @@ -229,6 +229,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/spfill.asm b/tests/functional/spfill.asm index fb3030fdc..652b5dada 100644 --- a/tests/functional/spfill.asm +++ b/tests/functional/spfill.asm @@ -507,6 +507,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/stoperr.asm b/tests/functional/stoperr.asm index 2be76523c..6d25cde12 100644 --- a/tests/functional/stoperr.asm +++ b/tests/functional/stoperr.asm @@ -56,6 +56,7 @@ __CALL_BACK__: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/storecstr.asm b/tests/functional/storecstr.asm index a613f3512..c3343987c 100644 --- a/tests/functional/storecstr.asm +++ b/tests/functional/storecstr.asm @@ -147,6 +147,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/storestr0.asm b/tests/functional/storestr0.asm index d776ba06b..02473c296 100644 --- a/tests/functional/storestr0.asm +++ b/tests/functional/storestr0.asm @@ -140,6 +140,7 @@ __CALL_BACK__: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/storestr1.asm b/tests/functional/storestr1.asm index f49371653..05c8899e9 100644 --- a/tests/functional/storestr1.asm +++ b/tests/functional/storestr1.asm @@ -504,6 +504,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/storestr2.asm b/tests/functional/storestr2.asm index fffb1fd45..acc935bd7 100644 --- a/tests/functional/storestr2.asm +++ b/tests/functional/storestr2.asm @@ -487,6 +487,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/str0.asm b/tests/functional/str0.asm index 5468ee6c1..f8c791150 100644 --- a/tests/functional/str0.asm +++ b/tests/functional/str0.asm @@ -510,6 +510,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/str00.asm b/tests/functional/str00.asm index 6b66923b0..76145f3c5 100644 --- a/tests/functional/str00.asm +++ b/tests/functional/str00.asm @@ -144,6 +144,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/str01.asm b/tests/functional/str01.asm index dd12b25ab..ee41e42c8 100644 --- a/tests/functional/str01.asm +++ b/tests/functional/str01.asm @@ -495,6 +495,7 @@ __STORE_STR2: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/str02.asm b/tests/functional/str02.asm index 3ab759a1c..cca21b52b 100644 --- a/tests/functional/str02.asm +++ b/tests/functional/str02.asm @@ -142,6 +142,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/stradd.asm b/tests/functional/stradd.asm index 415cfa0b5..741c93483 100644 --- a/tests/functional/stradd.asm +++ b/tests/functional/stradd.asm @@ -161,6 +161,7 @@ __LABEL1: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/strbase.asm b/tests/functional/strbase.asm index 6c91ed27e..cca27feea 100644 --- a/tests/functional/strbase.asm +++ b/tests/functional/strbase.asm @@ -636,6 +636,7 @@ __FREE_STR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/strbase2.asm b/tests/functional/strbase2.asm index 41bc0d083..81309c320 100644 --- a/tests/functional/strbase2.asm +++ b/tests/functional/strbase2.asm @@ -645,6 +645,7 @@ __FREE_STR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/stringfunc.asm b/tests/functional/stringfunc.asm index c1ebb02cb..692afd682 100644 --- a/tests/functional/stringfunc.asm +++ b/tests/functional/stringfunc.asm @@ -461,6 +461,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/stringparam.asm b/tests/functional/stringparam.asm index 46adf3f69..6cb244078 100644 --- a/tests/functional/stringparam.asm +++ b/tests/functional/stringparam.asm @@ -477,6 +477,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/strlocal0.asm b/tests/functional/strlocal0.asm index 5b3eb9be3..9104b31bd 100644 --- a/tests/functional/strlocal0.asm +++ b/tests/functional/strlocal0.asm @@ -508,6 +508,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/strparam0.asm b/tests/functional/strparam0.asm index da8a5a727..059207f67 100644 --- a/tests/functional/strparam0.asm +++ b/tests/functional/strparam0.asm @@ -507,6 +507,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/strparam1.asm b/tests/functional/strparam1.asm index a2814b633..1f35397a7 100644 --- a/tests/functional/strparam1.asm +++ b/tests/functional/strparam1.asm @@ -170,6 +170,7 @@ __LABEL0: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/strparam2.asm b/tests/functional/strparam2.asm index 931fb804d..96e4cd6a3 100644 --- a/tests/functional/strparam2.asm +++ b/tests/functional/strparam2.asm @@ -202,6 +202,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/strparam3.asm b/tests/functional/strparam3.asm index 30f547df0..80c2db5d7 100644 --- a/tests/functional/strparam3.asm +++ b/tests/functional/strparam3.asm @@ -501,6 +501,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/strsigil.asm b/tests/functional/strsigil.asm index 60218c2d1..b0771cd7e 100644 --- a/tests/functional/strsigil.asm +++ b/tests/functional/strsigil.asm @@ -641,6 +641,7 @@ __STRLEN: ; Direct FASTCALL entry ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/subrec.asm b/tests/functional/subrec.asm index 1927e0963..607739b94 100644 --- a/tests/functional/subrec.asm +++ b/tests/functional/subrec.asm @@ -343,6 +343,7 @@ __TO32BIT: ; Converts H'L'HLB'C'AC to DEHL (Discards H'L'HL) ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/substrlval.asm b/tests/functional/substrlval.asm index 248e9f3ac..7697cecf5 100644 --- a/tests/functional/substrlval.asm +++ b/tests/functional/substrlval.asm @@ -630,6 +630,7 @@ __FREE_STR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/usr0.asm b/tests/functional/usr0.asm index 4bd61fcd1..8096fec2a 100644 --- a/tests/functional/usr0.asm +++ b/tests/functional/usr0.asm @@ -153,6 +153,7 @@ __CLS_SCR: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 diff --git a/tests/functional/valcrash2.asm b/tests/functional/valcrash2.asm index 7b2cfe4f6..24b51befd 100644 --- a/tests/functional/valcrash2.asm +++ b/tests/functional/valcrash2.asm @@ -144,6 +144,7 @@ __CALL_BACK__: ERROR_NumberTooBig EQU 5 ERROR_InvalidArg EQU 9 ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 ERROR_InvalidFileName EQU 14 ERROR_InvalidColour EQU 19 ERROR_BreakIntoProgram EQU 20 From ed4749dc75b2418d6ca4ee6db5d74be03b8aaadf Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 6 Feb 2018 00:37:35 +0100 Subject: [PATCH 169/247] add mcleod BASIC eval routine! yay!! --- library/basic.bas | 146 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 library/basic.bas diff --git a/library/basic.bas b/library/basic.bas new file mode 100644 index 000000000..a777b314b --- /dev/null +++ b/library/basic.bas @@ -0,0 +1,146 @@ + +/' -------------------------------------------------------------------------------------- +BASIC Interpreter KEYIN command for Sinclair BASIC +A function to execute a string as a BASIC command +Copyright 2018 Miguel Angel Rodriguez Jodar (mcleod_ideafix). zxprojects.com + + Licensed under the Apache License, Version 2.0 (the "License") + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +USAGE: + +Build a string with valid BASIC tokens and pass it to the EvalBASIC() function +execute it. + +10 EvalBASIC("BEEP 1,20"): REM this will execute command BEEP 1,20 + +Multiple sentences can be executed as well: + +20 a = EvalBASIC("FOR n=0 TO 7: BORDER n: BEEP 0.1,n*8: NEXT n") + +Of course, the parameter can be any valid string parameter, so a BASIC program +can build a sentence or a group of sentences and execute them using this +function. Think of it as a even more versatile VAL or VAL$ function. + +Note that this function returns the value of the BC register. + +BUGS: +Most probably a lot. I'm still learning how to interact with the BASIC interpreter. +-------------------------------------------------------------------------------------- '/ + + +#ifndef __LIBRARY_EVALBASIC__ +REM Avoid recursive / multiple inclusion +#define __LIBRARY_EVALBASIC__ + +#pragma push(case_insensitive) +#pragma case_insensitive = true + +Function fastcall EvalBASIC(ByVal basic as String) as Uinteger + ASM + PROC + + LOCAL E_LINE + LOCAL CH_ADD + LOCAL SET_MIN + LOCAL MAKE_ROOM + LOCAL K_CUR + LOCAL LINE_SCAN + LOCAL LINE_RUN + LOCAL DEF_ADD + LOCAL NEWPPC + LOCAL NSPPC + LOCAL PPC + LOCAL SUBPPC + LOCAL NXTLIN + + E_LINE equ 5c59h + CH_ADD equ 5c5dh + SET_MIN equ 16b0h + MAKE_ROOM equ 1655h + K_CUR equ 5c5bh + LINE_SCAN equ 1b17h + LINE_RUN equ 1b8ah + DEF_ADD equ 5c0bh + NEWPPC equ 5c42h + NSPPC equ 5c44h + PPC equ 5c45h + SUBPPC equ 5c47h + NXTLIN equ 5c55h + + ld a, h + or l + ret z ; Empty (NULL) string? return + + ld de,(CH_ADD) ; Save some BASIC pointers + push de ; that will change while our string is + ld de,(NXTLIN) ; being executed, so at the end of it, + push de ; normal program can resume execution + ld de,(PPC) ; + push de ; + ld a,(SUBPPC) ; + push af ; + ld de,(NEWPPC) ; + push de ; + ld a,(NSPPC) ; + push af ; + push ix ; Not sure if IX is modified, but ... + + ld c, (hl) + inc hl + ld b, (hl) ; BC = string length + inc hl ; HL = start of string + push hl + push bc ; And save both address and length for future use + call SET_MIN ; Clear edit and work space + ld hl,(E_LINE) ; HL = start of editor area + pop bc ; Retrieve temporarily string address + push bc + call MAKE_ROOM ; Make room for BC bytes (length of the string) starting in the editor area (HL) + pop bc + pop hl ; Finally, retrieve both string address and length + ld de,(E_LINE) ; Destination: recently opened space in editor area + ldir ; Transfer string into there (key it in into editor) + ld (K_CUR),de ; Update K_CUR to point to the end of the "keyed in" line + call LINE_SCAN ; Check syntax + bit 7,(iy+0) ; If syntax error... + ld a, ERROR_NonsenseInBasic + jp z, __ERROR ; ... return with C Nonsense in BASIC + ld hl,(E_LINE) ; Copy the start of the now syntax clean line to execute + ld (CH_ADD),hl ; into CH_ADD to start executing + set 7,(iy+1) ; Signal we are going to execute a line + ld (iy+0),0xff ; Clear ERR-NO (OK) + ld (iy+10),1 ; Point NSPPC to the first statement into the line + call LINE_RUN ; Execute the line + + pop ix + pop af ; + ld (NSPPC),a ; Restore BASIC pointers + pop hl ; to resume execution of the + ld (NEWPPC),hl ; next line/sentence by the + pop af ; interpreter + ld (SUBPPC),a ; + pop hl ; + ld (PPC),hl ; + pop hl ; + ld (NXTLIN),hl ; + pop hl ; + ld (CH_ADD),hl ; + + ENDP + END ASM +End Function + +#pragma pop(case_insensitive) +#require "error.asm" + +#endif \ No newline at end of file From 3881e8316d658fd97ff2add53d0eded7324daf3b Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 6 Feb 2018 23:39:09 +0100 Subject: [PATCH 170/247] add eval.bas example This example shows how to call the ROM BASIC interpreter --- examples/eval.bas | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 examples/eval.bas diff --git a/examples/eval.bas b/examples/eval.bas new file mode 100644 index 000000000..3929e3b76 --- /dev/null +++ b/examples/eval.bas @@ -0,0 +1,17 @@ + +#include + +' Some Sinclair BASIC tokens ASCII codes +#define FOR_ 235 +#define TO_ 204 +#define BORDER_ 231 +#define PAUSE_ 242 +#define NEXT_ 243 + +REM Executes "FOR i = 0 TO 7: BORDER i: PAUSE 40: NEXT i" twice +FOR i = 1 TO 2 +EvalBasic(CHR$(FOR_, CODE "i", CODE "=", 48, TO_, 55, CODE ":", _ + BORDER_, CODE "i", CODE ":", PAUSE_, 52, 48, CODE ":", _ + NEXT_, CODE "i", 13)) +NEXT + From 84d8ba5a595f587e4d5151333c484337e5c5d309 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 6 Feb 2018 23:51:37 +0100 Subject: [PATCH 171/247] =?UTF-8?q?Bump=20version:=201.8.0=20=E2=86=92=201?= =?UTF-8?q?.8.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- ChangeLog | 9 +++++++++ version.py | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 64d6abfc3..edecd43f2 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,4 +1,4 @@ [bumpversion] -current_version = 1.8.0 +current_version = 1.8.1 files = version.py diff --git a/ChangeLog b/ChangeLog index 8777c1b2c..6a7744c9c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +================================================================ +Changes from Version 1.8.0 to 1.8.1 +! Bugfixes in the peephole optimizer +! Bugfix in OUT instruction ++ Fixes minor errors and bugs (i.e. --enable-break) ++ Improved and faster generated code (IN, OUT, AND, check BREAK...) +* Added basic.bas library (meta-interpreter) and eval.bas example!! + (thanks to @mcleod_ideafix!!!) + ================================================================ Changes from Version 1.7.2 to 1.8.0 ! Bugfixes in the peephole optimizer (-O3) diff --git a/version.py b/version.py index 5e2481568..8e066ca35 100755 --- a/version.py +++ b/version.py @@ -1 +1 @@ -VERSION = '1.8.0' +VERSION = '1.8.1' From 1ad3e67feecec9179774568236e1ef8e87406645 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 17 Feb 2018 13:57:56 +0100 Subject: [PATCH 172/247] optimize some logical operations This will shorten the generated code and make it faster for many expressions. --- arch/zx48k/backend/__init__.py | 11 +++++++++++ tests/functional/funcif.asm | 3 +-- tests/functional/opt3_lcd5.asm | 8 +++----- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/arch/zx48k/backend/__init__.py b/arch/zx48k/backend/__init__.py index fd4f6ea47..658746242 100644 --- a/arch/zx48k/backend/__init__.py +++ b/arch/zx48k/backend/__init__.py @@ -121,6 +121,7 @@ OPT21 = True OPT22 = True OPT23 = True +OPT24 = True # Label RegExp RE_LABEL = re.compile('^[ \t]*[a-zA-Z_][_a-zA-Z\d]*:') @@ -2595,6 +2596,16 @@ def output_join(output, new_chunk): changed = True continue + # Converts: + # or X | and X + # or a | and a + # Into: + # or X | and X + if OPT24 and i1 in ('and', 'or') and new_chunk[0] in ('or a', 'and a'): + new_chunk.pop(0) + changed = True + continue + changed, new_chunk = optiblock(new_chunk) output.extend(new_chunk) diff --git a/tests/functional/funcif.asm b/tests/functional/funcif.asm index f2dd569bc..0139d42a9 100644 --- a/tests/functional/funcif.asm +++ b/tests/functional/funcif.asm @@ -58,7 +58,6 @@ _ScanNear: ld h, a pop af or h - or a jp z, __LABEL1 ld (ix-1), 1 __LABEL1: @@ -183,7 +182,7 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A ld a, l ret -#line 65 "funcif.bas" +#line 64 "funcif.bas" ZXBASIC_USER_DATA: _x: diff --git a/tests/functional/opt3_lcd5.asm b/tests/functional/opt3_lcd5.asm index 06e2b8323..4a46a7ae1 100644 --- a/tests/functional/opt3_lcd5.asm +++ b/tests/functional/opt3_lcd5.asm @@ -213,7 +213,6 @@ _ScanNear: ld h, a pop af or h - or a jp z, __LABEL3 ld (ix-1), 1 __LABEL3: @@ -361,7 +360,6 @@ __LABEL3: ld h, a pop af or h - or a jp z, __LABEL5 ld a, (ix-1) ld h, 32 @@ -488,7 +486,7 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A ld a, l ret -#line 370 "opt3_lcd5.bas" +#line 368 "opt3_lcd5.bas" #line 1 "lei16.asm" __LEI16: @@ -507,7 +505,7 @@ checkParity: inc a ; True ret ENDP -#line 371 "opt3_lcd5.bas" +#line 369 "opt3_lcd5.bas" #line 1 "lti16.asm" #line 1 "lei8.asm" @@ -550,7 +548,7 @@ checkParity: inc a ; True ret ENDP -#line 372 "opt3_lcd5.bas" +#line 370 "opt3_lcd5.bas" ZXBASIC_USER_DATA: _x: From 8a13cd3a86771283b0b5a584d425690d63dd46ae Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 18 Feb 2018 12:26:51 +0100 Subject: [PATCH 173/247] improvement: optimize byte operations Whenever possible try to reduce asm operation on some byte operations (e.g. bAND, bOR, etc...) --- arch/zx48k/backend/__init__.py | 17 +++++++++++ tests/functional/band8.asm | 3 +- tests/functional/bor8.asm | 3 +- tests/functional/haplo06.asm | 52 ++++++++++++++++++++++++++++++++++ tests/functional/haplo06.bas | 8 ++++++ 5 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 tests/functional/haplo06.asm create mode 100644 tests/functional/haplo06.bas diff --git a/arch/zx48k/backend/__init__.py b/arch/zx48k/backend/__init__.py index 658746242..d26191d3f 100644 --- a/arch/zx48k/backend/__init__.py +++ b/arch/zx48k/backend/__init__.py @@ -122,6 +122,7 @@ OPT22 = True OPT23 = True OPT24 = True +OPT25 = True # Label RegExp RE_LABEL = re.compile('^[ \t]*[a-zA-Z_][_a-zA-Z\d]*:') @@ -2606,6 +2607,22 @@ def output_join(output, new_chunk): changed = True continue + # Converts: + # ld h, X (X != A) + # ld a, Y + # or/and/cp h + # Into: + # ld a, Y + # or/and/cp X + if OPT25 and i1 in ('cp', 'or', 'and') and o1[0] == 'h' and i0 == 'ld' and o0[0] == 'a' and len(output) > 2: + ii = inst(output[-3]) + oo = oper(output[-3]) + if ii == 'ld' and oo[0] == 'h' and oo[1] != 'a': + output[-1] = '{0} {1}'.format(i1, oo[1]) + output.pop(-3) + changed = True + continue + changed, new_chunk = optiblock(new_chunk) output.extend(new_chunk) diff --git a/tests/functional/band8.asm b/tests/functional/band8.asm index 546a9f035..f09da5ecd 100644 --- a/tests/functional/band8.asm +++ b/tests/functional/band8.asm @@ -13,9 +13,8 @@ __START_PROGRAM: ld a, (_a) xor a ld (_b), a - ld h, 1 ld a, (_a) - and h + and 1 ld (_b), a ld a, (_a) ld l, a diff --git a/tests/functional/bor8.asm b/tests/functional/bor8.asm index 7471a4190..1b030e2ac 100644 --- a/tests/functional/bor8.asm +++ b/tests/functional/bor8.asm @@ -12,9 +12,8 @@ __START_PROGRAM: ei ld a, (_a) ld (_b), a - ld h, 1 ld a, (_a) - or h + or 1 ld (_b), a ld a, (_a) ld a, 0FFh diff --git a/tests/functional/haplo06.asm b/tests/functional/haplo06.asm new file mode 100644 index 000000000..bd7c4b0e2 --- /dev/null +++ b/tests/functional/haplo06.asm @@ -0,0 +1,52 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, (_y) + ld a, (hl) + ld h, a + ld a, (_a) + or h + push af + ld hl, (_y) + inc hl + ld a, (hl) + ld h, a + pop af + or h + ld (_a), a + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 +_y: + DEFB 00, 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/haplo06.bas b/tests/functional/haplo06.bas new file mode 100644 index 000000000..0d50974da --- /dev/null +++ b/tests/functional/haplo06.bas @@ -0,0 +1,8 @@ + +DIM a as UByte +DIM y as Uinteger + +a = a bOR peek(y) bOR peek(y + 1) + + + From 7319682fdcfcc22dd71314f09bfd07d1e4795a90 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 20 Feb 2018 23:56:03 +0100 Subject: [PATCH 174/247] optimize inc / dec for bytes Expressions like a = a + 1 for byte/Ubyte are now much shorter even for local variables and parameters! --- arch/zx48k/backend/__init__.py | 54 +++++++++++++------ tests/functional/32.asm | 4 +- tests/functional/63.asm | 4 +- tests/functional/65.asm | 4 +- tests/functional/66.asm | 4 +- tests/functional/astore16.asm | 11 ++-- tests/functional/byte_neq.asm | 5 +- tests/functional/doloop.asm | 10 ++-- tests/functional/elseif3.asm | 7 ++- tests/functional/elseif5.asm | 7 ++- tests/functional/elseif6.asm | 7 ++- tests/functional/endif.asm | 5 +- tests/functional/equ8.asm | 5 +- tests/functional/fact.asm | 19 ++++--- tests/functional/for0.asm | 13 +++-- tests/functional/fornext.asm | 20 +++---- tests/functional/fornext2.asm | 5 +- tests/functional/fornextopt.asm | 10 ++-- tests/functional/fornextopt2.asm | 10 ++-- tests/functional/forsplitted.asm | 10 ++-- tests/functional/forsplitted0.asm | 12 ++--- tests/functional/forsplitted1.asm | 10 ++-- tests/functional/gti8.asm | 7 ++- tests/functional/gtu8.asm | 5 +- tests/functional/headerless.asm | 5 +- tests/functional/ifcoendif.asm | 7 ++- tests/functional/ifcoendif1.asm | 7 ++- tests/functional/ifcoendif2.asm | 5 +- tests/functional/ifelse2.asm | 22 ++++---- tests/functional/ifelse3.asm | 12 ++--- tests/functional/ifelse4.asm | 12 ++--- tests/functional/ifelse5.asm | 17 +++--- tests/functional/ifempty2.asm | 7 ++- tests/functional/ifempty3.asm | 12 ++--- tests/functional/ifempty5.asm | 5 +- tests/functional/ifempty6.asm | 5 +- tests/functional/ifemptyelse.asm | 5 +- tests/functional/ifemptylabel1.asm | 5 +- tests/functional/ifemptylabel2.asm | 5 +- tests/functional/iffor.asm | 7 ++- tests/functional/iffor1.asm | 7 ++- tests/functional/iffor2.asm | 17 +++--- tests/functional/ififelseelse1.asm | 27 ++++------ tests/functional/ififelseelse2.asm | 27 ++++------ tests/functional/ifline.asm | 5 +- tests/functional/ifthen.asm | 12 ++--- tests/functional/ifthencosntcoendif.asm | 5 +- tests/functional/ifthenelse.asm | 12 ++--- tests/functional/ifthenelseif.asm | 22 ++++---- tests/functional/ifthenlblsntcoendif.asm | 5 +- tests/functional/ifthensntcoelsecocoendif.asm | 12 ++--- tests/functional/ifthensntcoelsecoendif.asm | 12 ++--- tests/functional/ifthensntcoelselblco.asm | 10 ++-- tests/functional/ifthensntcoelselblcoco.asm | 10 ++-- tests/functional/ifthensntcoendif.asm | 5 +- tests/functional/ifwhile.asm | 7 ++- tests/functional/ifwhile1.asm | 7 ++- tests/functional/ifwhilex.asm | 11 ++-- tests/functional/memcpytest.asm | 13 +++-- tests/functional/nir.asm | 5 +- tests/functional/opt2_ifbyte.asm | 5 +- tests/functional/opt3_atoloinc.asm | 5 +- tests/functional/poke0.asm | 5 +- tests/functional/poke1.asm | 4 +- tests/functional/poke2.asm | 5 +- tests/functional/read10.asm | 22 ++++---- tests/functional/read5.asm | 21 ++++---- tests/functional/read8.asm | 21 ++++---- tests/functional/read9.asm | 25 +++++---- tests/functional/slice2.asm | 18 +++---- tests/functional/subrec.asm | 19 ++++--- tests/functional/whilefalse1.asm | 5 +- tests/functional/whiletrue.asm | 5 +- 73 files changed, 344 insertions(+), 433 deletions(-) diff --git a/arch/zx48k/backend/__init__.py b/arch/zx48k/backend/__init__.py index d26191d3f..309db3997 100644 --- a/arch/zx48k/backend/__init__.py +++ b/arch/zx48k/backend/__init__.py @@ -123,6 +123,7 @@ OPT23 = True OPT24 = True OPT25 = True +OPT26 = True # Label RegExp RE_LABEL = re.compile('^[ \t]*[a-zA-Z_][_a-zA-Z\d]*:') @@ -2363,6 +2364,13 @@ def output_join(output, new_chunk): else: a1 = i1 = o1 = None + if len(output) > 1: + a0 = output[-2] + i0 = inst(a0) + o0 = oper(a0) + else: + a0 = i0 = o0 = None + a2 = new_chunk[0] # Fist new output instruction i2 = inst(a2) o2 = oper(a2) @@ -2385,13 +2393,6 @@ def output_join(output, new_chunk): changed = True continue - if OPT02 and i1 == i2 == 'ld' and o1[0] == o2[1] and o2[0] == o1[1]: - # This and previous instruction are LD X, Y - # Ok, previous instruction is LD A, B and current is LD B, A. Remove this one. - new_chunk = new_chunk[1:] - changed = True - continue - if ( OPT03 and (i1 == 'sbc' and @@ -2462,9 +2463,6 @@ def output_join(output, new_chunk): # JP !, OTHER # LABEL: if OPT17 and len(output) > 1: - a0 = output[-2] - i0 = inst(a0) - o0 = oper(a0) if i0 == i1 == 'jp' \ and i2[-1] == ':' \ and condition(a0) in {'c', 'nc', 'z', 'nz'} \ @@ -2511,8 +2509,6 @@ def output_join(output, new_chunk): # jp nz, __LABEL if OPT19 and i1 == 'sub' and '1' in o1 and i2 == 'jp' and len(output) > 1: c2 = condition(new_chunk[0]) - a0 = output[-2] - i0 = inst(a0) if c2 in {'c', 'nc'}: cond = 'z' if c2 == 'c' else 'nz' new_chunk[0] = 'jp %s, %s' % (cond, o2[0]) @@ -2541,9 +2537,6 @@ def output_join(output, new_chunk): # ld r, (ix +/- n) if OPT22 and len(output) > 1 and i1 == 'ld' and o1[0] in 'bcdehl' and o1[1] == 'a' and \ (i2, o2) == ('pop', ['af', 'sp']): - a0 = output[-2] - i0 = inst(a0) - o0 = oper(a0) if (i0, o0[:1]) == ('ld', ['a']) and RE_IX_IDX.match(o0[1]): output.pop() # Removes ld r, a output.pop() # Removes ld a, (ix + n) @@ -2623,6 +2616,37 @@ def output_join(output, new_chunk): changed = True continue + # Converts: + # ld a, (nn) | ld a, (ix+N) + # inc/dec a + # ld (nn), a | ld (ix+N), a + # Into: + # ld hl, _n | + # inc/dec (hl) | inc/dec (ix+N) + if OPT26 and i1 in ('inc', 'dec') and o1[0] == 'a' and i0 == i2 == 'ld' and \ + (o0[0], o0[1]) == (o2[1], o2[0]) and o0[1][0] == '(': + new_chunk.pop(0) + if RE_IX_IDX.match(o0[1]): + output[-1] = '{0} {1}'.format(i1, o0[1]) + output.pop(-2) + else: + output[-1] = '{0} (hl)'.format(i1) + output[-2] = 'ld hl, {0}'.format(o0[1][1:-1]) + changed = True + continue + + # Converts: + # ld X, Y + # ld Y, X + # Into: + # ld X, Y + if OPT02 and i1 == i2 == 'ld' and o1[0] == o2[1] and o2[0] == o1[1]: + # This and previous instruction are LD X, Y + # Ok, previous instruction is LD A, B and current is LD B, A. Remove this one. + new_chunk = new_chunk[1:] + changed = True + continue + changed, new_chunk = optiblock(new_chunk) output.extend(new_chunk) diff --git a/tests/functional/32.asm b/tests/functional/32.asm index d0923cdbf..e3bb9e78e 100644 --- a/tests/functional/32.asm +++ b/tests/functional/32.asm @@ -30,9 +30,7 @@ _test: push ix ld ix, 0 add ix, sp - ld a, (ix+5) - inc a - ld (ix+5), a + inc (ix+5) _test__leave: ld sp, ix pop ix diff --git a/tests/functional/63.asm b/tests/functional/63.asm index cadc64b15..ebb557f41 100644 --- a/tests/functional/63.asm +++ b/tests/functional/63.asm @@ -34,9 +34,7 @@ _test: push ix ld ix, 0 add ix, sp - ld a, (ix+5) - inc a - ld (ix+5), a + inc (ix+5) _test__leave: ld sp, ix pop ix diff --git a/tests/functional/65.asm b/tests/functional/65.asm index 4367aac7a..1421a06ce 100644 --- a/tests/functional/65.asm +++ b/tests/functional/65.asm @@ -30,9 +30,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 _test: - ld a, (ix+5) - inc a - ld (ix+5), a + inc (ix+5) _test__leave: ret diff --git a/tests/functional/66.asm b/tests/functional/66.asm index e2952139f..a48eeb9fa 100644 --- a/tests/functional/66.asm +++ b/tests/functional/66.asm @@ -36,9 +36,7 @@ __END_PROGRAM: __CALL_BACK__: DEFW 0 _test: - ld a, (ix+5) - inc a - ld (ix+5), a + inc (ix+5) _test__leave: ret diff --git a/tests/functional/astore16.asm b/tests/functional/astore16.asm index 5d9a483d6..3c59a2cbb 100644 --- a/tests/functional/astore16.asm +++ b/tests/functional/astore16.asm @@ -37,9 +37,8 @@ __LABEL3: call __PRINTU16 call PRINT_EOL __LABEL4: - ld a, (_i) - inc a - ld (_i), a + ld hl, _i + inc (hl) __LABEL0: ld a, 15 ld hl, (_i - 1) @@ -264,7 +263,7 @@ __FNMUL2: ENDP -#line 53 "astore16.bas" +#line 52 "astore16.bas" #line 1 "print.asm" ; vim:ts=4:sw=4:et: @@ -1388,7 +1387,7 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ENDP -#line 54 "astore16.bas" +#line 53 "astore16.bas" #line 1 "printu16.asm" #line 1 "printi16.asm" @@ -1590,7 +1589,7 @@ __PRINTU_LOOP: #line 2 "printu16.asm" -#line 55 "astore16.bas" +#line 54 "astore16.bas" ZXBASIC_USER_DATA: _i: diff --git a/tests/functional/byte_neq.asm b/tests/functional/byte_neq.asm index 9842453a7..4adda95d9 100644 --- a/tests/functional/byte_neq.asm +++ b/tests/functional/byte_neq.asm @@ -13,9 +13,8 @@ __START_PROGRAM: ld a, (_a) sub 5 jp z, __LABEL1 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL1: ld hl, 0 ld b, h diff --git a/tests/functional/doloop.asm b/tests/functional/doloop.asm index 98bf9bbc9..39cac0be1 100644 --- a/tests/functional/doloop.asm +++ b/tests/functional/doloop.asm @@ -21,16 +21,14 @@ __LABEL3: __LABEL__30: __LABEL4: __LABEL__40: - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL__50: jp __LABEL4 __LABEL5: __LABEL6: - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) jp __LABEL6 __LABEL7: ld hl, 0 diff --git a/tests/functional/elseif3.asm b/tests/functional/elseif3.asm index 02ef0e9a3..135800f17 100644 --- a/tests/functional/elseif3.asm +++ b/tests/functional/elseif3.asm @@ -21,9 +21,8 @@ __LABEL0: call __LTI8 or a jp z, __LABEL3 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL3: __LABEL1: ld hl, 0 @@ -68,7 +67,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 34 "elseif3.bas" +#line 33 "elseif3.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/elseif5.asm b/tests/functional/elseif5.asm index 7a476ab02..c80afa493 100644 --- a/tests/functional/elseif5.asm +++ b/tests/functional/elseif5.asm @@ -25,9 +25,8 @@ __LABEL2: ld a, (_a) or a jp nz, __LABEL5 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL5: __LABEL3: __LABEL1: @@ -73,7 +72,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 39 "elseif5.bas" +#line 38 "elseif5.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/elseif6.asm b/tests/functional/elseif6.asm index 667da2109..91f68b964 100644 --- a/tests/functional/elseif6.asm +++ b/tests/functional/elseif6.asm @@ -15,9 +15,8 @@ __START_PROGRAM: call __LTI8 or a jp z, __LABEL1 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL1: ld hl, 0 ld b, h @@ -61,7 +60,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 27 "elseif6.bas" +#line 26 "elseif6.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/endif.asm b/tests/functional/endif.asm index 23c038c6d..98014556c 100644 --- a/tests/functional/endif.asm +++ b/tests/functional/endif.asm @@ -14,9 +14,8 @@ __START_PROGRAM: ld a, (_a) cp h jp nc, __LABEL1 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL1: ld hl, 0 ld b, h diff --git a/tests/functional/equ8.asm b/tests/functional/equ8.asm index d9073e90d..18dd25220 100644 --- a/tests/functional/equ8.asm +++ b/tests/functional/equ8.asm @@ -13,9 +13,8 @@ __START_PROGRAM: ld a, (_a) sub 5 jp nz, __LABEL1 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL1: ld hl, 0 ld b, h diff --git a/tests/functional/fact.asm b/tests/functional/fact.asm index aa68f8423..a068dea03 100644 --- a/tests/functional/fact.asm +++ b/tests/functional/fact.asm @@ -38,9 +38,8 @@ __LABEL3: call __PRINTU32 call PRINT_EOL __LABEL4: - ld a, (_x) - inc a - ld (_x), a + ld hl, _x + inc (hl) __LABEL0: ld a, 10 ld hl, (_x - 1) @@ -205,7 +204,7 @@ __CLS_SCR: ; to get the start of the screen ENDP -#line 111 "fact.bas" +#line 110 "fact.bas" #line 1 "mul32.asm" #line 1 "_mul32.asm" @@ -298,7 +297,7 @@ __TO32BIT: ; Converts H'L'HLB'C'AC to DEHL (Discards H'L'HL) ret -#line 112 "fact.bas" +#line 111 "fact.bas" #line 1 "print.asm" ; vim:ts=4:sw=4:et: @@ -1340,7 +1339,7 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ENDP -#line 113 "fact.bas" +#line 112 "fact.bas" #line 1 "printstr.asm" @@ -1717,7 +1716,7 @@ __PRINT_STR: ENDP -#line 114 "fact.bas" +#line 113 "fact.bas" #line 1 "printu32.asm" #line 1 "printi32.asm" @@ -1982,7 +1981,7 @@ __PRINTU_LOOP: #line 2 "printu32.asm" -#line 115 "fact.bas" +#line 114 "fact.bas" #line 1 "printu8.asm" #line 1 "printi8.asm" @@ -2116,7 +2115,7 @@ __PRINTU_LOOP: #line 2 "printu8.asm" -#line 116 "fact.bas" +#line 115 "fact.bas" #line 1 "sub32.asm" ; SUB32 @@ -2146,7 +2145,7 @@ __SUB32: push bc ; puts return address back exx ret -#line 117 "fact.bas" +#line 116 "fact.bas" ZXBASIC_USER_DATA: _x: diff --git a/tests/functional/for0.asm b/tests/functional/for0.asm index 289aa31df..6b9cc7e5b 100644 --- a/tests/functional/for0.asm +++ b/tests/functional/for0.asm @@ -25,9 +25,8 @@ __LABEL3: xor a call __PRINTSTR __LABEL4: - ld a, (_x) - inc a - ld (_x), a + ld hl, _x + inc (hl) __LABEL0: ld a, 126 ld hl, (_x - 1) @@ -136,7 +135,7 @@ __CLS_SCR: ; to get the start of the screen ENDP -#line 42 "for0.bas" +#line 41 "for0.bas" #line 1 "lti8.asm" #line 1 "lei8.asm" @@ -163,7 +162,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 43 "for0.bas" +#line 42 "for0.bas" #line 1 "printi8.asm" #line 1 "printnum.asm" @@ -1370,7 +1369,7 @@ __PRINTU_LOOP: ENDP -#line 44 "for0.bas" +#line 43 "for0.bas" #line 1 "printstr.asm" @@ -1747,7 +1746,7 @@ __PRINT_STR: ENDP -#line 45 "for0.bas" +#line 44 "for0.bas" ZXBASIC_USER_DATA: _x: diff --git a/tests/functional/fornext.asm b/tests/functional/fornext.asm index 4e608e5a1..c7905c56e 100644 --- a/tests/functional/fornext.asm +++ b/tests/functional/fornext.asm @@ -17,9 +17,8 @@ __LABEL__10: __LABEL3: __LABEL__20: __LABEL4: - ld a, (_i) - inc a - ld (_i), a + ld hl, _i + inc (hl) __LABEL0: ld a, 10 ld hl, (_i - 1) @@ -33,9 +32,8 @@ __LABEL__30: __LABEL8: __LABEL__40: __LABEL9: - ld a, (_i) - inc a - ld (_i), a + ld hl, _i + inc (hl) __LABEL5: ld a, 10 ld hl, (_i - 1) @@ -47,9 +45,8 @@ __LABEL7: jp __LABEL10 __LABEL13: __LABEL14: - ld a, (_i) - inc a - ld (_i), a + ld hl, _i + inc (hl) __LABEL10: ld a, 10 ld hl, (_i - 1) @@ -61,9 +58,8 @@ __LABEL12: jp __LABEL15 __LABEL18: __LABEL19: - ld a, (_i) - inc a - ld (_i), a + ld hl, _i + inc (hl) __LABEL15: ld a, 10 ld hl, (_i - 1) diff --git a/tests/functional/fornext2.asm b/tests/functional/fornext2.asm index 7f973bba3..99fa3d77f 100644 --- a/tests/functional/fornext2.asm +++ b/tests/functional/fornext2.asm @@ -37,9 +37,8 @@ _test: jp __LABEL0 __LABEL3: __LABEL4: - ld a, (_x) - inc a - ld (_x), a + ld hl, _x + inc (hl) __LABEL0: ld a, 6 ld hl, (_x - 1) diff --git a/tests/functional/fornextopt.asm b/tests/functional/fornextopt.asm index 6a28e83e5..1fd16a021 100644 --- a/tests/functional/fornextopt.asm +++ b/tests/functional/fornextopt.asm @@ -15,13 +15,11 @@ __START_PROGRAM: jp __LABEL0 __LABEL3: __LABEL__lbl: - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL4: - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL0: xor a ld hl, (_a - 1) diff --git a/tests/functional/fornextopt2.asm b/tests/functional/fornextopt2.asm index da7bab325..d121c888d 100644 --- a/tests/functional/fornextopt2.asm +++ b/tests/functional/fornextopt2.asm @@ -15,13 +15,11 @@ __START_PROGRAM: jp __LABEL0 __LABEL3: __LABEL__lbl: - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL4: - ld a, (_a) - dec a - ld (_a), a + ld hl, _a + dec (hl) __LABEL0: ld h, 11 ld a, (_a) diff --git a/tests/functional/forsplitted.asm b/tests/functional/forsplitted.asm index b4672f6b4..ccbbb0e07 100644 --- a/tests/functional/forsplitted.asm +++ b/tests/functional/forsplitted.asm @@ -23,9 +23,8 @@ __LABEL__40: xor a ld (_M), a __LABEL9: - ld a, (_m) - inc a - ld (_m), a + ld hl, _m + inc (hl) __LABEL5: ld a, 6 ld hl, (_m - 1) @@ -33,9 +32,8 @@ __LABEL5: jp nc, __LABEL8 __LABEL7: __LABEL4: - ld a, (_i) - inc a - ld (_i), a + ld hl, _i + inc (hl) __LABEL0: ld a, 8 ld hl, (_i - 1) diff --git a/tests/functional/forsplitted0.asm b/tests/functional/forsplitted0.asm index cdc57714f..bf3649445 100644 --- a/tests/functional/forsplitted0.asm +++ b/tests/functional/forsplitted0.asm @@ -17,13 +17,11 @@ __LABEL__20: jp __LABEL0 __LABEL3: __LABEL__30: - ld a, (_i) - inc a - ld (_i), a + ld hl, _i + inc (hl) __LABEL4: - ld a, (_i) - inc a - ld (_i), a + ld hl, _i + inc (hl) __LABEL0: ld a, 10 ld hl, (_i - 1) @@ -73,7 +71,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 39 "forsplitted0.bas" +#line 37 "forsplitted0.bas" ZXBASIC_USER_DATA: _i: diff --git a/tests/functional/forsplitted1.asm b/tests/functional/forsplitted1.asm index 329cb1ae9..4969356b9 100644 --- a/tests/functional/forsplitted1.asm +++ b/tests/functional/forsplitted1.asm @@ -21,9 +21,8 @@ __LABEL8: xor a ld (_M), a __LABEL9: - ld a, (_m) - inc a - ld (_m), a + ld hl, _m + inc (hl) __LABEL5: ld a, 6 ld hl, (_m - 1) @@ -31,9 +30,8 @@ __LABEL5: jp nc, __LABEL8 __LABEL7: __LABEL4: - ld a, (_i) - inc a - ld (_i), a + ld hl, _i + inc (hl) __LABEL0: ld a, 8 ld hl, (_i - 1) diff --git a/tests/functional/gti8.asm b/tests/functional/gti8.asm index 926b7ccf5..83be61bc9 100644 --- a/tests/functional/gti8.asm +++ b/tests/functional/gti8.asm @@ -15,9 +15,8 @@ __START_PROGRAM: call __LTI8 or a jp z, __LABEL1 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL1: ld hl, 0 ld b, h @@ -61,7 +60,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 27 "gti8.bas" +#line 26 "gti8.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/gtu8.asm b/tests/functional/gtu8.asm index e27cc2be7..db432d77a 100644 --- a/tests/functional/gtu8.asm +++ b/tests/functional/gtu8.asm @@ -14,9 +14,8 @@ __START_PROGRAM: ld hl, (_a - 1) cp h jp nc, __LABEL1 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL1: ld hl, 0 ld b, h diff --git a/tests/functional/headerless.asm b/tests/functional/headerless.asm index b49ecb8b4..f1c514445 100644 --- a/tests/functional/headerless.asm +++ b/tests/functional/headerless.asm @@ -1,6 +1,5 @@ - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) ld hl, 0 ld b, h ld c, l diff --git a/tests/functional/ifcoendif.asm b/tests/functional/ifcoendif.asm index 272f7d136..b2f9fa4d8 100644 --- a/tests/functional/ifcoendif.asm +++ b/tests/functional/ifcoendif.asm @@ -15,9 +15,8 @@ __START_PROGRAM: call __LTI8 or a jp z, __LABEL1 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL1: ld hl, 0 ld b, h @@ -61,7 +60,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 27 "ifcoendif.bas" +#line 26 "ifcoendif.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/ifcoendif1.asm b/tests/functional/ifcoendif1.asm index 3a064b5bc..dcc0e2d27 100644 --- a/tests/functional/ifcoendif1.asm +++ b/tests/functional/ifcoendif1.asm @@ -15,9 +15,8 @@ __START_PROGRAM: call __LTI8 or a jp z, __LABEL1 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL1: ld hl, 0 ld b, h @@ -61,7 +60,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 27 "ifcoendif1.bas" +#line 26 "ifcoendif1.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/ifcoendif2.asm b/tests/functional/ifcoendif2.asm index 9b17225e1..3ce344591 100644 --- a/tests/functional/ifcoendif2.asm +++ b/tests/functional/ifcoendif2.asm @@ -14,9 +14,8 @@ __START_PROGRAM: ld a, (_a) cp h jp nc, __LABEL1 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL1: ld hl, 0 ld b, h diff --git a/tests/functional/ifelse2.asm b/tests/functional/ifelse2.asm index 500813d1f..186b9c5c7 100644 --- a/tests/functional/ifelse2.asm +++ b/tests/functional/ifelse2.asm @@ -15,28 +15,24 @@ __START_PROGRAM: call __LTI8 or a jp z, __LABEL0 - ld a, (_i) - inc a - ld (_i), a + ld hl, _i + inc (hl) jp __LABEL1 __LABEL0: - ld a, (_i) - dec a - ld (_i), a + ld hl, _i + dec (hl) __LABEL1: ld h, 0 ld a, (_i) call __LTI8 or a jp z, __LABEL2 - ld a, (_i) - inc a - ld (_i), a + ld hl, _i + inc (hl) jp __LABEL3 __LABEL2: - ld a, (_i) - dec a - ld (_i), a + ld hl, _i + dec (hl) __LABEL3: ld hl, 0 ld b, h @@ -80,7 +76,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 46 "ifelse2.bas" +#line 42 "ifelse2.bas" ZXBASIC_USER_DATA: _i: diff --git a/tests/functional/ifelse3.asm b/tests/functional/ifelse3.asm index f7ee16152..d295819a3 100644 --- a/tests/functional/ifelse3.asm +++ b/tests/functional/ifelse3.asm @@ -15,14 +15,12 @@ __START_PROGRAM: call __LTI8 or a jp z, __LABEL0 - ld a, (_i) - inc a - ld (_i), a + ld hl, _i + inc (hl) jp __LABEL1 __LABEL0: - ld a, (_i) - dec a - ld (_i), a + ld hl, _i + dec (hl) __LABEL1: ld hl, 0 ld b, h @@ -66,7 +64,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 32 "ifelse3.bas" +#line 30 "ifelse3.bas" ZXBASIC_USER_DATA: _i: diff --git a/tests/functional/ifelse4.asm b/tests/functional/ifelse4.asm index 1e0fc0a94..3fdf4a49e 100644 --- a/tests/functional/ifelse4.asm +++ b/tests/functional/ifelse4.asm @@ -15,14 +15,12 @@ __START_PROGRAM: call __LTI8 or a jp z, __LABEL0 - ld a, (_i) - inc a - ld (_i), a + ld hl, _i + inc (hl) jp __LABEL1 __LABEL0: - ld a, (_i) - dec a - ld (_i), a + ld hl, _i + dec (hl) __LABEL1: ld hl, 0 ld b, h @@ -66,7 +64,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 32 "ifelse4.bas" +#line 30 "ifelse4.bas" ZXBASIC_USER_DATA: _i: diff --git a/tests/functional/ifelse5.asm b/tests/functional/ifelse5.asm index a92740b9c..65fb3f74c 100644 --- a/tests/functional/ifelse5.asm +++ b/tests/functional/ifelse5.asm @@ -15,22 +15,19 @@ __START_PROGRAM: call __LTI8 or a jp z, __LABEL0 - ld a, (_i) - inc a - ld (_i), a + ld hl, _i + inc (hl) jp __LABEL1 __LABEL0: - ld a, (_i) - dec a - ld (_i), a + ld hl, _i + dec (hl) ld h, 2 ld a, (_i) call __LTI8 or a jp z, __LABEL3 - ld a, (_i) - inc a - ld (_i), a + ld hl, _i + inc (hl) __LABEL3: __LABEL1: ld hl, 0 @@ -75,7 +72,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 41 "ifelse5.bas" +#line 38 "ifelse5.bas" ZXBASIC_USER_DATA: _i: diff --git a/tests/functional/ifempty2.asm b/tests/functional/ifempty2.asm index 9a842732a..7dca57f38 100644 --- a/tests/functional/ifempty2.asm +++ b/tests/functional/ifempty2.asm @@ -16,9 +16,8 @@ __START_PROGRAM: or a jp nz, __LABEL1 __LABEL0: - ld a, (_i) - inc a - ld (_i), a + ld hl, _i + inc (hl) __LABEL1: ld hl, 0 ld b, h @@ -62,7 +61,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 28 "ifempty2.bas" +#line 27 "ifempty2.bas" ZXBASIC_USER_DATA: _i: diff --git a/tests/functional/ifempty3.asm b/tests/functional/ifempty3.asm index 25088ecf5..9a28da5ab 100644 --- a/tests/functional/ifempty3.asm +++ b/tests/functional/ifempty3.asm @@ -15,14 +15,12 @@ __START_PROGRAM: call __LTI8 or a jp z, __LABEL0 - ld a, (_i) - dec a - ld (_i), a + ld hl, _i + dec (hl) jp __LABEL1 __LABEL0: - ld a, (_i) - inc a - ld (_i), a + ld hl, _i + inc (hl) __LABEL1: ld hl, 0 ld b, h @@ -66,7 +64,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 32 "ifempty3.bas" +#line 30 "ifempty3.bas" ZXBASIC_USER_DATA: _i: diff --git a/tests/functional/ifempty5.asm b/tests/functional/ifempty5.asm index 57667f023..787eec908 100644 --- a/tests/functional/ifempty5.asm +++ b/tests/functional/ifempty5.asm @@ -10,9 +10,8 @@ __START_PROGRAM: add hl, sp ld (__CALL_BACK__), hl ei - ld a, (_i) - inc a - ld (_i), a + ld hl, _i + inc (hl) ld hl, 0 ld b, h ld c, l diff --git a/tests/functional/ifempty6.asm b/tests/functional/ifempty6.asm index a5cebffce..698cf25af 100644 --- a/tests/functional/ifempty6.asm +++ b/tests/functional/ifempty6.asm @@ -10,9 +10,8 @@ __START_PROGRAM: add hl, sp ld (__CALL_BACK__), hl ei - ld a, (_i) - dec a - ld (_i), a + ld hl, _i + dec (hl) ld hl, 0 ld b, h ld c, l diff --git a/tests/functional/ifemptyelse.asm b/tests/functional/ifemptyelse.asm index 5b6a84841..463f474fa 100644 --- a/tests/functional/ifemptyelse.asm +++ b/tests/functional/ifemptyelse.asm @@ -10,9 +10,8 @@ __START_PROGRAM: add hl, sp ld (__CALL_BACK__), hl ei - ld a, (_a) - dec a - ld (_a), a + ld hl, _a + dec (hl) ld hl, 0 ld b, h ld c, l diff --git a/tests/functional/ifemptylabel1.asm b/tests/functional/ifemptylabel1.asm index 4121eaeb8..e797ba471 100644 --- a/tests/functional/ifemptylabel1.asm +++ b/tests/functional/ifemptylabel1.asm @@ -12,9 +12,8 @@ __START_PROGRAM: ei jp __LABEL1 __LABEL__Here: - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL1: jp __LABEL__Here ld hl, 0 diff --git a/tests/functional/ifemptylabel2.asm b/tests/functional/ifemptylabel2.asm index 085d796dd..7b3378bf2 100644 --- a/tests/functional/ifemptylabel2.asm +++ b/tests/functional/ifemptylabel2.asm @@ -10,9 +10,8 @@ __START_PROGRAM: add hl, sp ld (__CALL_BACK__), hl ei - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) jp __LABEL1 __LABEL0: __LABEL__Here: diff --git a/tests/functional/iffor.asm b/tests/functional/iffor.asm index 2200bea6c..eba92444b 100644 --- a/tests/functional/iffor.asm +++ b/tests/functional/iffor.asm @@ -20,9 +20,8 @@ __START_PROGRAM: jp __LABEL2 __LABEL5: __LABEL6: - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL2: ld a, 10 ld hl, (_a - 1) @@ -73,7 +72,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 39 "iffor.bas" +#line 38 "iffor.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/iffor1.asm b/tests/functional/iffor1.asm index aa2a3db91..034ee1f9d 100644 --- a/tests/functional/iffor1.asm +++ b/tests/functional/iffor1.asm @@ -20,9 +20,8 @@ __START_PROGRAM: jp __LABEL2 __LABEL5: __LABEL6: - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL2: ld a, 10 ld hl, (_a - 1) @@ -73,7 +72,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 39 "iffor1.bas" +#line 38 "iffor1.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/iffor2.asm b/tests/functional/iffor2.asm index d0f5d5c57..a92c013bd 100644 --- a/tests/functional/iffor2.asm +++ b/tests/functional/iffor2.asm @@ -24,15 +24,13 @@ __LABEL5: call __LTI8 or a jp z, __LABEL8 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) jp __LABEL9 __LABEL12: __LABEL13: - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL9: ld a, 10 ld hl, (_a - 1) @@ -42,9 +40,8 @@ __LABEL9: __LABEL11: __LABEL8: __LABEL6: - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL2: ld a, 10 ld hl, (_a - 1) @@ -95,7 +92,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 61 "iffor2.bas" +#line 58 "iffor2.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/ififelseelse1.asm b/tests/functional/ififelseelse1.asm index 26835b4b9..3e6ea45c1 100644 --- a/tests/functional/ififelseelse1.asm +++ b/tests/functional/ififelseelse1.asm @@ -17,33 +17,28 @@ __LABEL__20: call __LTI8 or a jp z, __LABEL0 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) ld h, 10 ld a, (_a) call __LTI8 or a jp z, __LABEL2 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) jp __LABEL3 __LABEL2: - ld a, (_a) - dec a - ld (_a), a + ld hl, _a + dec (hl) __LABEL3: jp __LABEL1 __LABEL0: - ld a, (_a) - dec a - ld (_a), a + ld hl, _a + dec (hl) __LABEL1: __LABEL__30: - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) ld hl, 0 ld b, h ld c, l @@ -86,7 +81,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 52 "ififelseelse1.bas" +#line 47 "ififelseelse1.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/ififelseelse2.asm b/tests/functional/ififelseelse2.asm index e5802dcd6..c8e642efd 100644 --- a/tests/functional/ififelseelse2.asm +++ b/tests/functional/ififelseelse2.asm @@ -17,33 +17,28 @@ __LABEL__20: call __LTI8 or a jp z, __LABEL0 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) ld h, 10 ld a, (_a) call __LTI8 or a jp z, __LABEL2 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) jp __LABEL3 __LABEL2: - ld a, (_a) - dec a - ld (_a), a + ld hl, _a + dec (hl) __LABEL3: jp __LABEL1 __LABEL0: - ld a, (_a) - dec a - ld (_a), a + ld hl, _a + dec (hl) __LABEL1: __LABEL__30: - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) ld hl, 0 ld b, h ld c, l @@ -86,7 +81,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 52 "ififelseelse2.bas" +#line 47 "ififelseelse2.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/ifline.asm b/tests/functional/ifline.asm index 63478dcf1..ce56cc573 100644 --- a/tests/functional/ifline.asm +++ b/tests/functional/ifline.asm @@ -13,9 +13,8 @@ __START_PROGRAM: ld a, (_a) dec a jp nz, __LABEL1 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL1: ld hl, 0 ld b, h diff --git a/tests/functional/ifthen.asm b/tests/functional/ifthen.asm index 47d00eb57..6573705de 100644 --- a/tests/functional/ifthen.asm +++ b/tests/functional/ifthen.asm @@ -18,9 +18,8 @@ __LABEL__10: or a jp z, __LABEL1 __LABEL__20: - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL__30: __LABEL1: ld h, 1 @@ -28,9 +27,8 @@ __LABEL1: call __LTI8 or a jp z, __LABEL3 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL3: ld hl, 0 ld b, h @@ -74,7 +72,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 40 "ifthen.bas" +#line 38 "ifthen.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/ifthencosntcoendif.asm b/tests/functional/ifthencosntcoendif.asm index 23c038c6d..98014556c 100644 --- a/tests/functional/ifthencosntcoendif.asm +++ b/tests/functional/ifthencosntcoendif.asm @@ -14,9 +14,8 @@ __START_PROGRAM: ld a, (_a) cp h jp nc, __LABEL1 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL1: ld hl, 0 ld b, h diff --git a/tests/functional/ifthenelse.asm b/tests/functional/ifthenelse.asm index f8e4da478..4124e502b 100644 --- a/tests/functional/ifthenelse.asm +++ b/tests/functional/ifthenelse.asm @@ -17,9 +17,8 @@ __LABEL__10: call __LTI8 or a jp z, __LABEL0 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL__20: jp __LABEL1 __LABEL0: @@ -32,9 +31,8 @@ __LABEL1: call __LTI8 or a jp z, __LABEL2 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) jp __LABEL3 __LABEL2: xor a @@ -82,7 +80,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 48 "ifthenelse.bas" +#line 46 "ifthenelse.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/ifthenelseif.asm b/tests/functional/ifthenelseif.asm index 28faf8f6e..ed231ff55 100644 --- a/tests/functional/ifthenelseif.asm +++ b/tests/functional/ifthenelseif.asm @@ -17,9 +17,8 @@ __LABEL__10: call __LTI8 or a jp z, __LABEL0 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL__20: jp __LABEL1 __LABEL0: @@ -39,9 +38,8 @@ __LABEL__40: call __LTI8 or a jp z, __LABEL4 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL__50: jp __LABEL5 __LABEL4: @@ -68,9 +66,8 @@ __LABEL5: call __LTI8 or a jp z, __LABEL10 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) jp __LABEL11 __LABEL10: xor a @@ -87,9 +84,8 @@ __LABEL11: call __LTI8 or a jp z, __LABEL14 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) jp __LABEL15 __LABEL14: xor a @@ -151,7 +147,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 117 "ifthenelseif.bas" +#line 113 "ifthenelseif.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/ifthenlblsntcoendif.asm b/tests/functional/ifthenlblsntcoendif.asm index 831b04f9c..f75b84ac5 100644 --- a/tests/functional/ifthenlblsntcoendif.asm +++ b/tests/functional/ifthenlblsntcoendif.asm @@ -15,9 +15,8 @@ __START_PROGRAM: cp h jp nc, __LABEL1 __LABEL__10: - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL1: ld hl, 0 ld b, h diff --git a/tests/functional/ifthensntcoelsecocoendif.asm b/tests/functional/ifthensntcoelsecocoendif.asm index ed571ee79..98958b32d 100644 --- a/tests/functional/ifthensntcoelsecocoendif.asm +++ b/tests/functional/ifthensntcoelsecocoendif.asm @@ -15,14 +15,12 @@ __START_PROGRAM: call __LTI8 or a jp z, __LABEL0 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) jp __LABEL1 __LABEL0: - ld a, (_a) - dec a - ld (_a), a + ld hl, _a + dec (hl) __LABEL1: ld hl, 0 ld b, h @@ -66,7 +64,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 32 "ifthensntcoelsecocoendif.bas" +#line 30 "ifthensntcoelsecocoendif.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/ifthensntcoelsecoendif.asm b/tests/functional/ifthensntcoelsecoendif.asm index 27e56de5a..bca293e2d 100644 --- a/tests/functional/ifthensntcoelsecoendif.asm +++ b/tests/functional/ifthensntcoelsecoendif.asm @@ -15,14 +15,12 @@ __START_PROGRAM: call __LTI8 or a jp z, __LABEL0 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) jp __LABEL1 __LABEL0: - ld a, (_a) - dec a - ld (_a), a + ld hl, _a + dec (hl) __LABEL1: ld hl, 0 ld b, h @@ -66,7 +64,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 32 "ifthensntcoelsecoendif.bas" +#line 30 "ifthensntcoelsecoendif.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/ifthensntcoelselblco.asm b/tests/functional/ifthensntcoelselblco.asm index f7a857f25..42d7259a2 100644 --- a/tests/functional/ifthensntcoelselblco.asm +++ b/tests/functional/ifthensntcoelselblco.asm @@ -15,15 +15,13 @@ __START_PROGRAM: cp h jp nc, __LABEL0 __LABEL__10: - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) jp __LABEL1 __LABEL0: __LABEL__30: - ld a, (_a) - dec a - ld (_a), a + ld hl, _a + dec (hl) __LABEL1: ld hl, 0 ld b, h diff --git a/tests/functional/ifthensntcoelselblcoco.asm b/tests/functional/ifthensntcoelselblcoco.asm index f7a857f25..42d7259a2 100644 --- a/tests/functional/ifthensntcoelselblcoco.asm +++ b/tests/functional/ifthensntcoelselblcoco.asm @@ -15,15 +15,13 @@ __START_PROGRAM: cp h jp nc, __LABEL0 __LABEL__10: - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) jp __LABEL1 __LABEL0: __LABEL__30: - ld a, (_a) - dec a - ld (_a), a + ld hl, _a + dec (hl) __LABEL1: ld hl, 0 ld b, h diff --git a/tests/functional/ifthensntcoendif.asm b/tests/functional/ifthensntcoendif.asm index 23c038c6d..98014556c 100644 --- a/tests/functional/ifthensntcoendif.asm +++ b/tests/functional/ifthensntcoendif.asm @@ -14,9 +14,8 @@ __START_PROGRAM: ld a, (_a) cp h jp nc, __LABEL1 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL1: ld hl, 0 ld b, h diff --git a/tests/functional/ifwhile.asm b/tests/functional/ifwhile.asm index e517a3533..6a913e7f7 100644 --- a/tests/functional/ifwhile.asm +++ b/tests/functional/ifwhile.asm @@ -21,9 +21,8 @@ __LABEL2: call __LTI8 or a jp z, __LABEL3 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) jp __LABEL2 __LABEL3: __LABEL1: @@ -69,7 +68,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 35 "ifwhile.bas" +#line 34 "ifwhile.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/ifwhile1.asm b/tests/functional/ifwhile1.asm index 977932817..c46da3a09 100644 --- a/tests/functional/ifwhile1.asm +++ b/tests/functional/ifwhile1.asm @@ -21,9 +21,8 @@ __LABEL2: call __LTI8 or a jp z, __LABEL3 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) jp __LABEL2 __LABEL3: __LABEL1: @@ -69,7 +68,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 35 "ifwhile1.bas" +#line 34 "ifwhile1.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/ifwhilex.asm b/tests/functional/ifwhilex.asm index 4c0162001..dc4929b24 100644 --- a/tests/functional/ifwhilex.asm +++ b/tests/functional/ifwhilex.asm @@ -22,9 +22,8 @@ __LABEL2: call __LTI8 or a jp z, __LABEL3 - ld a, (_i) - inc a - ld (_i), a + ld hl, _i + inc (hl) jp __LABEL2 __LABEL3: ld a, (_i) @@ -73,7 +72,7 @@ checkParity: ret ENDP #line 2 "lti8.asm" -#line 38 "ifwhilex.bas" +#line 37 "ifwhilex.bas" #line 1 "print.asm" ; vim:ts=4:sw=4:et: @@ -1197,7 +1196,7 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ENDP -#line 39 "ifwhilex.bas" +#line 38 "ifwhilex.bas" #line 1 "printi8.asm" #line 1 "printnum.asm" @@ -1363,7 +1362,7 @@ __PRINTU_LOOP: ENDP -#line 40 "ifwhilex.bas" +#line 39 "ifwhilex.bas" ZXBASIC_USER_DATA: _i: diff --git a/tests/functional/memcpytest.asm b/tests/functional/memcpytest.asm index d4504a72e..81855f7cb 100644 --- a/tests/functional/memcpytest.asm +++ b/tests/functional/memcpytest.asm @@ -23,9 +23,8 @@ __LABEL3: xor a call __PRINTSTR __LABEL4: - ld a, (_i) - inc a - ld (_i), a + ld hl, _i + inc (hl) __LABEL0: ld a, 10 ld hl, (_i - 1) @@ -198,7 +197,7 @@ __CLS_SCR: ; to get the start of the screen ENDP -#line 104 "memcpytest.bas" +#line 103 "memcpytest.bas" #line 1 "memcopy.asm" ; ---------------------------------------------------------------- @@ -250,7 +249,7 @@ __MEMCPY2: ret ENDP -#line 105 "memcpytest.bas" +#line 104 "memcpytest.bas" #line 1 "pause.asm" ; The PAUSE statement (Calling the ROM) @@ -259,7 +258,7 @@ __PAUSE: ld b, h ld c, l jp 1F3Dh ; PAUSE_1 -#line 106 "memcpytest.bas" +#line 105 "memcpytest.bas" #line 1 "printstr.asm" #line 1 "print.asm" @@ -1677,7 +1676,7 @@ __PRINT_STR: ENDP -#line 107 "memcpytest.bas" +#line 106 "memcpytest.bas" ZXBASIC_USER_DATA: _i: diff --git a/tests/functional/nir.asm b/tests/functional/nir.asm index 4eee829b0..1f6155def 100644 --- a/tests/functional/nir.asm +++ b/tests/functional/nir.asm @@ -22,9 +22,8 @@ __LABEL5: xor a ld (3), a __LABEL6: - ld a, (_sprite) - inc a - ld (_sprite), a + ld hl, _sprite + inc (hl) __LABEL2: ld a, 7 ld hl, (_sprite - 1) diff --git a/tests/functional/opt2_ifbyte.asm b/tests/functional/opt2_ifbyte.asm index e0968e795..858b86e0e 100644 --- a/tests/functional/opt2_ifbyte.asm +++ b/tests/functional/opt2_ifbyte.asm @@ -13,9 +13,8 @@ __START_PROGRAM: ld a, (_a) sub 64 jp nz, __LABEL1 - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) __LABEL1: ld hl, 0 ld b, h diff --git a/tests/functional/opt3_atoloinc.asm b/tests/functional/opt3_atoloinc.asm index f173e4acc..c4d35207c 100644 --- a/tests/functional/opt3_atoloinc.asm +++ b/tests/functional/opt3_atoloinc.asm @@ -23,8 +23,9 @@ __START_PROGRAM: ld (_doorstate), a ld a, (_doorid) ld (_doorstate), a - inc a - ld (_nfires), a + ld hl, _nfires + inc (hl) + ld a, (_key) ld (_level), a ld a, (_doorstate) ld (_nfires), a diff --git a/tests/functional/poke0.asm b/tests/functional/poke0.asm index 08c1c3f4f..085bdd700 100644 --- a/tests/functional/poke0.asm +++ b/tests/functional/poke0.asm @@ -21,9 +21,8 @@ __LABEL3: inc hl ld (_i), hl __LABEL4: - ld a, (_j) - inc a - ld (_j), a + ld hl, _j + inc (hl) __LABEL0: ld a, 250 ld hl, (_j - 1) diff --git a/tests/functional/poke1.asm b/tests/functional/poke1.asm index bd47e6118..2b9cfddc2 100644 --- a/tests/functional/poke1.asm +++ b/tests/functional/poke1.asm @@ -61,9 +61,7 @@ __LABEL3: ld (ix-3), l ld (ix-2), h __LABEL4: - ld a, (ix-1) - inc a - ld (ix-1), a + inc (ix-1) __LABEL0: ld a, (ix-1) push af diff --git a/tests/functional/poke2.asm b/tests/functional/poke2.asm index 08c1c3f4f..085bdd700 100644 --- a/tests/functional/poke2.asm +++ b/tests/functional/poke2.asm @@ -21,9 +21,8 @@ __LABEL3: inc hl ld (_i), hl __LABEL4: - ld a, (_j) - inc a - ld (_j), a + ld hl, _j + inc (hl) __LABEL0: ld a, 250 ld hl, (_j - 1) diff --git a/tests/functional/read10.asm b/tests/functional/read10.asm index ce8409622..7544b1a37 100644 --- a/tests/functional/read10.asm +++ b/tests/functional/read10.asm @@ -56,9 +56,7 @@ __LABEL3: call __PRINTF call PRINT_EOL __LABEL4: - ld a, (ix-1) - inc a - ld (ix-1), a + inc (ix-1) __LABEL0: ld a, (ix-1) push af @@ -203,7 +201,7 @@ __MULF: ; Multiplication jp __FPSTACK_POP -#line 121 "read10.bas" +#line 119 "read10.bas" #line 1 "ploadf.asm" ; Parameter / Local var load @@ -249,7 +247,7 @@ __PLOADF: add hl, de jp __LOADF -#line 122 "read10.bas" +#line 120 "read10.bas" #line 1 "pow.asm" @@ -283,7 +281,7 @@ __POW: ; Exponentiation ENDP -#line 123 "read10.bas" +#line 121 "read10.bas" #line 1 "print.asm" ; vim:ts=4:sw=4:et: @@ -1407,7 +1405,7 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ENDP -#line 124 "read10.bas" +#line 122 "read10.bas" #line 1 "printf.asm" #line 1 "printstr.asm" @@ -1829,7 +1827,7 @@ __PRINTF: ; Prints a Fixed point Number stored in C ED LH ENDP -#line 125 "read10.bas" +#line 123 "read10.bas" #line 1 "pstoref.asm" ; Stores FP number in A ED CB at location HL+IX @@ -1879,7 +1877,7 @@ __PSTOREF: pop de jp __STOREF -#line 126 "read10.bas" +#line 124 "read10.bas" #line 1 "read_restore.asm" ;; This implements READ & RESTORE functions @@ -2776,7 +2774,7 @@ __DATA_ADDR: ;; Stores current DATA ptr -#line 127 "read10.bas" +#line 125 "read10.bas" #line 1 "sin.asm" @@ -2790,7 +2788,7 @@ SIN: ; Computes SIN using ROM FP-CALC jp __FPSTACK_POP -#line 128 "read10.bas" +#line 126 "read10.bas" #line 1 "tan.asm" @@ -2804,7 +2802,7 @@ TAN: ; Computes TAN using ROM FP-CALC jp __FPSTACK_POP -#line 129 "read10.bas" +#line 127 "read10.bas" ZXBASIC_USER_DATA: _v: diff --git a/tests/functional/read5.asm b/tests/functional/read5.asm index ca6edd78c..0b0d9e6fe 100644 --- a/tests/functional/read5.asm +++ b/tests/functional/read5.asm @@ -39,9 +39,8 @@ __LABEL3: call __PRINTF call PRINT_EOL __LABEL4: - ld a, (_i) - inc a - ld (_i), a + ld hl, _i + inc (hl) __LABEL0: ld a, 4 ld hl, (_i - 1) @@ -196,7 +195,7 @@ __MULF: ; Multiplication jp __FPSTACK_POP -#line 114 "read5.bas" +#line 113 "read5.bas" #line 1 "pow.asm" @@ -230,7 +229,7 @@ __POW: ; Exponentiation ENDP -#line 115 "read5.bas" +#line 114 "read5.bas" #line 1 "print.asm" ; vim:ts=4:sw=4:et: @@ -1354,7 +1353,7 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ENDP -#line 116 "read5.bas" +#line 115 "read5.bas" #line 1 "printf.asm" #line 1 "printstr.asm" @@ -1776,7 +1775,7 @@ __PRINTF: ; Prints a Fixed point Number stored in C ED LH ENDP -#line 117 "read5.bas" +#line 116 "read5.bas" #line 1 "read_restore.asm" ;; This implements READ & RESTORE functions @@ -2703,7 +2702,7 @@ __DATA_ADDR: ;; Stores current DATA ptr -#line 118 "read5.bas" +#line 117 "read5.bas" #line 1 "sin.asm" @@ -2717,7 +2716,7 @@ SIN: ; Computes SIN using ROM FP-CALC jp __FPSTACK_POP -#line 119 "read5.bas" +#line 118 "read5.bas" #line 1 "storef.asm" __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) @@ -2748,7 +2747,7 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), b ret -#line 120 "read5.bas" +#line 119 "read5.bas" #line 1 "tan.asm" @@ -2762,7 +2761,7 @@ TAN: ; Computes TAN using ROM FP-CALC jp __FPSTACK_POP -#line 121 "read5.bas" +#line 120 "read5.bas" ZXBASIC_USER_DATA: _v: diff --git a/tests/functional/read8.asm b/tests/functional/read8.asm index 16c83b7ec..cc7e85170 100644 --- a/tests/functional/read8.asm +++ b/tests/functional/read8.asm @@ -30,9 +30,8 @@ __LABEL3: call __PRINTF call PRINT_EOL __LABEL4: - ld a, (_i) - inc a - ld (_i), a + ld hl, _i + inc (hl) __LABEL0: ld a, 4 ld hl, (_i - 1) @@ -187,7 +186,7 @@ __MULF: ; Multiplication jp __FPSTACK_POP -#line 105 "read8.bas" +#line 104 "read8.bas" #line 1 "pow.asm" @@ -221,7 +220,7 @@ __POW: ; Exponentiation ENDP -#line 106 "read8.bas" +#line 105 "read8.bas" #line 1 "print.asm" ; vim:ts=4:sw=4:et: @@ -1345,7 +1344,7 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ENDP -#line 107 "read8.bas" +#line 106 "read8.bas" #line 1 "printf.asm" #line 1 "printstr.asm" @@ -1767,7 +1766,7 @@ __PRINTF: ; Prints a Fixed point Number stored in C ED LH ENDP -#line 108 "read8.bas" +#line 107 "read8.bas" #line 1 "read_restore.asm" ;; This implements READ & RESTORE functions @@ -2694,7 +2693,7 @@ __DATA_ADDR: ;; Stores current DATA ptr -#line 109 "read8.bas" +#line 108 "read8.bas" #line 1 "sin.asm" @@ -2708,7 +2707,7 @@ SIN: ; Computes SIN using ROM FP-CALC jp __FPSTACK_POP -#line 110 "read8.bas" +#line 109 "read8.bas" #line 1 "storef.asm" __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) @@ -2739,7 +2738,7 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), b ret -#line 111 "read8.bas" +#line 110 "read8.bas" #line 1 "tan.asm" @@ -2753,7 +2752,7 @@ TAN: ; Computes TAN using ROM FP-CALC jp __FPSTACK_POP -#line 112 "read8.bas" +#line 111 "read8.bas" ZXBASIC_USER_DATA: _v: diff --git a/tests/functional/read9.asm b/tests/functional/read9.asm index 3696965e7..1c154dff7 100644 --- a/tests/functional/read9.asm +++ b/tests/functional/read9.asm @@ -45,9 +45,8 @@ __LABEL3: call __PRINTF call PRINT_EOL __LABEL4: - ld a, (_i) - inc a - ld (_i), a + ld hl, _i + inc (hl) __LABEL0: ld a, 3 ld hl, (_i - 1) @@ -334,7 +333,7 @@ __FNMUL2: ENDP -#line 120 "read9.bas" +#line 119 "read9.bas" #line 1 "iloadf.asm" ; __FASTCALL__ routine which @@ -365,7 +364,7 @@ __LOADF: ; Loads a 40 bits FP number from address pointed by HL ld b, (hl) ret -#line 121 "read9.bas" +#line 120 "read9.bas" #line 1 "mulf.asm" #line 1 "stackf.asm" @@ -436,7 +435,7 @@ __MULF: ; Multiplication jp __FPSTACK_POP -#line 122 "read9.bas" +#line 121 "read9.bas" #line 1 "pow.asm" @@ -470,7 +469,7 @@ __POW: ; Exponentiation ENDP -#line 123 "read9.bas" +#line 122 "read9.bas" #line 1 "print.asm" ; vim:ts=4:sw=4:et: @@ -1594,7 +1593,7 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ENDP -#line 124 "read9.bas" +#line 123 "read9.bas" #line 1 "printf.asm" #line 1 "printstr.asm" @@ -2016,7 +2015,7 @@ __PRINTF: ; Prints a Fixed point Number stored in C ED LH ENDP -#line 125 "read9.bas" +#line 124 "read9.bas" #line 1 "read_restore.asm" ;; This implements READ & RESTORE functions @@ -2913,7 +2912,7 @@ __DATA_ADDR: ;; Stores current DATA ptr -#line 126 "read9.bas" +#line 125 "read9.bas" #line 1 "sin.asm" @@ -2927,7 +2926,7 @@ SIN: ; Computes SIN using ROM FP-CALC jp __FPSTACK_POP -#line 127 "read9.bas" +#line 126 "read9.bas" #line 1 "storef.asm" __PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) @@ -2958,7 +2957,7 @@ __STOREF: ; Stores the given FP number in A EDCB at address HL ld (hl), b ret -#line 128 "read9.bas" +#line 127 "read9.bas" #line 1 "tan.asm" @@ -2972,7 +2971,7 @@ TAN: ; Computes TAN using ROM FP-CALC jp __FPSTACK_POP -#line 129 "read9.bas" +#line 128 "read9.bas" ZXBASIC_USER_DATA: _v: diff --git a/tests/functional/slice2.asm b/tests/functional/slice2.asm index cf06faaf7..253cdd1e1 100644 --- a/tests/functional/slice2.asm +++ b/tests/functional/slice2.asm @@ -76,9 +76,7 @@ __LABEL4: add a, 2 ld (ix+7), a __LABEL5: - ld a, (ix-1) - inc a - ld (ix-1), a + inc (ix-1) __LABEL1: ld a, (ix-1) push af @@ -206,7 +204,7 @@ __CLS_SCR: ; to get the start of the screen ENDP -#line 113 "slice2.bas" +#line 111 "slice2.bas" #line 1 "error.asm" ; Simple error control routines @@ -249,7 +247,7 @@ __ERROR_CODE: __STOP: ld (ERR_NR), a ret -#line 114 "slice2.bas" +#line 112 "slice2.bas" #line 1 "free.asm" ; vim: ts=4:et:sw=4: @@ -568,7 +566,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ENDP -#line 115 "slice2.bas" +#line 113 "slice2.bas" #line 1 "loadstr.asm" #line 1 "alloc.asm" @@ -799,7 +797,7 @@ __LOADSTR: ; __FASTCALL__ entry ldir ; Copies string (length number included) pop hl ; Recovers destiny in hl as result ret -#line 116 "slice2.bas" +#line 114 "slice2.bas" #line 1 "pstorestr2.asm" ; vim:ts=4:et:sw=4 @@ -858,7 +856,7 @@ __PSTORE_STR2: add hl, bc jp __STORE_STR2 -#line 117 "slice2.bas" +#line 115 "slice2.bas" #line 1 "strlen.asm" ; Returns len if a string @@ -877,7 +875,7 @@ __STRLEN: ; Direct FASTCALL entry ret -#line 118 "slice2.bas" +#line 116 "slice2.bas" #line 1 "strslice.asm" ; String slicing library @@ -986,7 +984,7 @@ __FREE_ON_EXIT: ENDP -#line 119 "slice2.bas" +#line 117 "slice2.bas" ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: diff --git a/tests/functional/subrec.asm b/tests/functional/subrec.asm index 607739b94..25ef05074 100644 --- a/tests/functional/subrec.asm +++ b/tests/functional/subrec.asm @@ -44,9 +44,8 @@ __LABEL3: call __PRINTU32 call PRINT_EOL __LABEL4: - ld a, (_x) - inc a - ld (_x), a + ld hl, _x + inc (hl) __LABEL0: ld a, 10 ld hl, (_x - 1) @@ -216,7 +215,7 @@ __CLS_SCR: ; to get the start of the screen ENDP -#line 122 "subrec.bas" +#line 121 "subrec.bas" #line 1 "mul32.asm" #line 1 "_mul32.asm" @@ -309,7 +308,7 @@ __TO32BIT: ; Converts H'L'HLB'C'AC to DEHL (Discards H'L'HL) ret -#line 123 "subrec.bas" +#line 122 "subrec.bas" #line 1 "print.asm" ; vim:ts=4:sw=4:et: @@ -1351,7 +1350,7 @@ __PRINT_TABLE: ; Jump table for 0 .. 22 codes ENDP -#line 124 "subrec.bas" +#line 123 "subrec.bas" #line 1 "printstr.asm" @@ -1728,7 +1727,7 @@ __PRINT_STR: ENDP -#line 125 "subrec.bas" +#line 124 "subrec.bas" #line 1 "printu32.asm" #line 1 "printi32.asm" @@ -1993,7 +1992,7 @@ __PRINTU_LOOP: #line 2 "printu32.asm" -#line 126 "subrec.bas" +#line 125 "subrec.bas" #line 1 "printu8.asm" #line 1 "printi8.asm" @@ -2127,7 +2126,7 @@ __PRINTU_LOOP: #line 2 "printu8.asm" -#line 127 "subrec.bas" +#line 126 "subrec.bas" #line 1 "sub32.asm" ; SUB32 @@ -2157,7 +2156,7 @@ __SUB32: push bc ; puts return address back exx ret -#line 128 "subrec.bas" +#line 127 "subrec.bas" ZXBASIC_USER_DATA: _result: diff --git a/tests/functional/whilefalse1.asm b/tests/functional/whilefalse1.asm index bed5b7fc7..864cacbff 100644 --- a/tests/functional/whilefalse1.asm +++ b/tests/functional/whilefalse1.asm @@ -13,9 +13,8 @@ __START_PROGRAM: __LABEL0: jp __LABEL1 __LABEL__BAD: - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) jp __LABEL0 __LABEL1: jp __LABEL__BAD diff --git a/tests/functional/whiletrue.asm b/tests/functional/whiletrue.asm index 4a34e96b0..5484805be 100644 --- a/tests/functional/whiletrue.asm +++ b/tests/functional/whiletrue.asm @@ -11,9 +11,8 @@ __START_PROGRAM: ld (__CALL_BACK__), hl ei __LABEL0: - ld a, (_a) - inc a - ld (_a), a + ld hl, _a + inc (hl) jp __LABEL0 __LABEL1: ld hl, 0 From cf48b011339c58caed053583610f9deef851a19e Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 19 Feb 2018 00:21:09 +0100 Subject: [PATCH 175/247] optimize local byte operations This applies mostly to local vars and parameters. --- arch/zx48k/backend/__init__.py | 12 ++++++++ tests/functional/opt2_ifbor2.asm | 52 ++++++++++++++++++++++++++++++++ tests/functional/opt2_ifbor2.bas | 7 +++++ tests/functional/opt3_lcd5.asm | 15 ++++----- 4 files changed, 77 insertions(+), 9 deletions(-) create mode 100644 tests/functional/opt2_ifbor2.asm create mode 100644 tests/functional/opt2_ifbor2.bas diff --git a/arch/zx48k/backend/__init__.py b/arch/zx48k/backend/__init__.py index 309db3997..75d5d9676 100644 --- a/arch/zx48k/backend/__init__.py +++ b/arch/zx48k/backend/__init__.py @@ -124,6 +124,7 @@ OPT24 = True OPT25 = True OPT26 = True +OPT27 = True # Label RegExp RE_LABEL = re.compile('^[ \t]*[a-zA-Z_][_a-zA-Z\d]*:') @@ -2647,6 +2648,17 @@ def output_join(output, new_chunk): changed = True continue + # Converts: + # ld h, X + # or/and h + # Into: + # or/and X + if OPT27 and i1 == 'ld' and o1[0] == 'h' and i2 in ('and', 'or') and o2[0] == 'h': + output.pop() + new_chunk[0] = '{0} {1}'.format(i2, o1[1]) + changed = True + continue + changed, new_chunk = optiblock(new_chunk) output.extend(new_chunk) diff --git a/tests/functional/opt2_ifbor2.asm b/tests/functional/opt2_ifbor2.asm new file mode 100644 index 000000000..1513f6d9f --- /dev/null +++ b/tests/functional/opt2_ifbor2.asm @@ -0,0 +1,52 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call _x + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + pop iy + pop ix + exx + ei + ret +__CALL_BACK__: + DEFW 0 +_x: + push ix + ld ix, 0 + add ix, sp + ld hl, 0 + push hl + inc sp + ld a, (ix-1) + or 1 + jp z, __LABEL1 + inc (ix-1) +__LABEL1: +_x__leave: + ld sp, ix + pop ix + ret + +ZXBASIC_USER_DATA: + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/opt2_ifbor2.bas b/tests/functional/opt2_ifbor2.bas new file mode 100644 index 000000000..d09073de6 --- /dev/null +++ b/tests/functional/opt2_ifbor2.bas @@ -0,0 +1,7 @@ + +SUB x +DIM a as Ubyte +IF a bOR 1 THEN a = a + 1 +END SUB + +x diff --git a/tests/functional/opt3_lcd5.asm b/tests/functional/opt3_lcd5.asm index 4a46a7ae1..aefa3dd44 100644 --- a/tests/functional/opt3_lcd5.asm +++ b/tests/functional/opt3_lcd5.asm @@ -118,8 +118,7 @@ __LABEL8: ld (ix-2), l ld (ix-1), h ld a, (hl) - ld h, (ix+9) - and h + and (ix+9) jp _ScanField__leave jp __LABEL1 __LABEL0: @@ -159,9 +158,8 @@ _SetField: ld (ix-1), h push hl ld a, (hl) - ld h, (ix+9) - or h pop hl + or (ix+9) ld (hl), a _SetField__leave: ld sp, ix @@ -362,8 +360,7 @@ __LABEL3: or h jp z, __LABEL5 ld a, (ix-1) - ld h, 32 - or h + or 32 ld (ix-1), a __LABEL5: ld a, (ix-1) @@ -486,7 +483,7 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A ld a, l ret -#line 368 "opt3_lcd5.bas" +#line 365 "opt3_lcd5.bas" #line 1 "lei16.asm" __LEI16: @@ -505,7 +502,7 @@ checkParity: inc a ; True ret ENDP -#line 369 "opt3_lcd5.bas" +#line 366 "opt3_lcd5.bas" #line 1 "lti16.asm" #line 1 "lei8.asm" @@ -548,7 +545,7 @@ checkParity: inc a ; True ret ENDP -#line 370 "opt3_lcd5.bas" +#line 367 "opt3_lcd5.bas" ZXBASIC_USER_DATA: _x: From a070c7c645e9fc505c069d5b9133b2e0e09b33a3 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 19 Feb 2018 23:54:14 +0100 Subject: [PATCH 176/247] add more byte optimizations Even more done! --- arch/zx48k/backend/__init__.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/zx48k/backend/__init__.py b/arch/zx48k/backend/__init__.py index 75d5d9676..76476161c 100644 --- a/arch/zx48k/backend/__init__.py +++ b/arch/zx48k/backend/__init__.py @@ -125,6 +125,7 @@ OPT25 = True OPT26 = True OPT27 = True +OPT28 = True # Label RegExp RE_LABEL = re.compile('^[ \t]*[a-zA-Z_][_a-zA-Z\d]*:') @@ -2659,6 +2660,23 @@ def output_join(output, new_chunk): changed = True continue + # Converts + # ld a, r|(ix+/-N)|(hl) + # ld h, a + # ld a, XXX | pop af + # Into: + # ld h, r|(ix+/-N)|(hl) + # ld a, XXX | pop af + if OPT28 and i1 == i0 == 'ld' and o0[0] == 'a' and \ + (o0[1] in ('a', 'b', 'c', 'd', 'e', 'h', 'l', '(hl)') or RE_IX_IDX.match(o0[1])) and \ + (o1[0], o1[1]) == ('h', 'a') and new_chunk and (new_chunk[0] == 'pop af' or + i2 == 'ld' and o2[0] == 'a'): + + output.pop() + output[-1] = 'ld h, {0}'.format(o0[1]) + changed = True + continue + changed, new_chunk = optiblock(new_chunk) output.extend(new_chunk) From e4c416da8258fda2b90da3b7173890ab09363889 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 20 Feb 2018 22:13:10 +0100 Subject: [PATCH 177/247] bugfix: O3 optimizer has several bugs * Several bugfixes in the -O3 optimizer (detroys updated) * Some operators were wrong * SUB and ADD does not use F flag (operands). --- arch/zx48k/optimizer.py | 63 ++++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 16 deletions(-) diff --git a/arch/zx48k/optimizer.py b/arch/zx48k/optimizer.py index d8aac69c1..b49d2d246 100644 --- a/arch/zx48k/optimizer.py +++ b/arch/zx48k/optimizer.py @@ -204,15 +204,22 @@ def oper(inst): elif I in {'push', 'pop', 'call'}: op.append('sp') # Sp is also affected by push, pop and call - elif I in {'or', 'and', 'xor', 'neg', 'cpl', 'rrca', 'rlca', 'rra', 'rla'}: - op.extend(['a', 'f', 'af']) + elif I in {'or', 'and', 'xor', 'neg', 'cpl', 'rrca', 'rlca'}: + op.append('a') + + elif I in {'rra', 'rla'}: + op.extend(['a', 'f']) elif I in ('rr', 'rl'): op.append('f') - elif I in {'add', 'adc', 'sub', 'sbc'}: + elif I in {'adc', 'sbc'}: + if len(op) == 1: + op = ['a', 'f'] + op + + elif I in {'add', 'sub'}: if len(op) == 1: - op = ['a', 'f'] + op + ['af'] + op = ['a'] + op elif I in {'ldd', 'ldi', 'lddr', 'ldir'}: op = ['hl', 'de', 'bc'] @@ -995,7 +1002,10 @@ def destroys(self): elif i in {'ccf', 'scf', 'bit', 'cp'}: res.add('f') elif i in {'or', 'and', 'xor', 'add', 'adc', 'sub', 'sbc'}: - res.update(single_registers(o[0])) + if len(o) > 1: + res.update(single_registers(o[0])) + else: + res.add('a') res.add('f') elif i in {'neg', 'cpl', 'daa', 'rra', 'rla', 'rrca', 'rlca', 'rrd', 'rld'}: res.update('a', 'f') @@ -1545,19 +1555,39 @@ def is_used(self, regs, i, top=None): return result - def requires(self, i=0): + def safe_to_write(self, regs, i=0, end_=0): + """ Given a list of registers (8 or 16 bits) returns a list of them + that are safe to modify from the given index until the position given + which, if omitted, defaults to the end of the block. + :param regs: register or iterable of registers (8 or 16 bit one) + :param i: initial position of the block to examine + :param end_: final position to examine + :returns: registers safe to write + """ + if is_register(regs): + regs = set(single_registers(regs)) + else: + regs = set(single_registers(x) for x in regs) + return not regs.intersection(self.requires(i, end_)) + + def requires(self, i=0, end_=None): """ Returns a list of registers and variables this block requires. By default checks from the beginning (i = 0). + :param i: initial position of the block to examine + :param end_: final position to examine + :returns: registers safe to write """ - regs = ['a', 'b', 'c', 'd', 'e', 'h', 'l', 'i', 'ixh', 'ixl', 'iyh', 'iyl', 'sp'] - top = len(self) + if i < 0: + i = 0 + end_ = len(self) if end_ is None or end_ > len(self) else end_ + regs = {'a', 'b', 'c', 'd', 'e', 'f', 'h', 'l', 'i', 'ixh', 'ixl', 'iyh', 'iyl', 'sp'} result = [] - for ii in range(i, top): + for ii in range(i, end_): for r in self.mem[ii].requires: r = r.lower() if r in regs: - result += [r] + result.append(r) regs.remove(r) for r in self.mem[ii].destroys: @@ -1565,7 +1595,7 @@ def requires(self, i=0): if r in regs: regs.remove(r) - if regs == []: + if not regs: break return result @@ -1574,18 +1604,17 @@ def destroys(self, i=0): """ Returns a list of registers this block destroys By default checks from the beginning (i = 0). """ - regs = ['a', 'b', 'c', 'd', 'e', 'h', 'l', 'i', 'ixh', 'ixl', 'iyh', 'iyl', 'sp'] + regs = {'a', 'b', 'c', 'd', 'e', 'f', 'h', 'l', 'i', 'ixh', 'ixl', 'iyh', 'iyl', 'sp'} top = len(self) result = [] for ii in range(i, top): for r in self.mem[ii].destroys: if r in regs: - result += [r] + result.append(r) regs.remove(r) - break - if regs == []: + if not regs: break return result @@ -1860,7 +1889,9 @@ def optimize(self): break if OPT16 and i > 0 and not self.mem[i - 1].is_label and i1 == 'pop' and \ - not self.mem[i - 1].affects([o1[0], 'sp']) and not self.mem[i - 1].needs([o1[0], 'sp']): + (not self.mem[i - 1].affects([o1[0], 'sp']) or + self.safe_to_write(o1[0], i + 1)) and \ + not self.mem[i - 1].needs([o1[0], 'sp']): # { ; POP X } => { POP X; } ; if inst does not uses X tmp = str(self.asm) self.swap(i - 1, i) From 71d9863e422e3ccc53f323269ef97aaa8bd35088 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Thu, 22 Feb 2018 00:26:00 +0100 Subject: [PATCH 178/247] add 2 more byte optimization This speeds ups some cases by removing useless instructions. --- arch/zx48k/backend/__init__.py | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/arch/zx48k/backend/__init__.py b/arch/zx48k/backend/__init__.py index 76476161c..c3b5f4911 100644 --- a/arch/zx48k/backend/__init__.py +++ b/arch/zx48k/backend/__init__.py @@ -126,6 +126,8 @@ OPT26 = True OPT27 = True OPT28 = True +OPT29 = True +OPT30 = True # Label RegExp RE_LABEL = re.compile('^[ \t]*[a-zA-Z_][_a-zA-Z\d]*:') @@ -2605,11 +2607,14 @@ def output_join(output, new_chunk): # Converts: # ld h, X (X != A) # ld a, Y - # or/and/cp h + # or/and/cp/add/sub h # Into: # ld a, Y # or/and/cp X - if OPT25 and i1 in ('cp', 'or', 'and') and o1[0] == 'h' and i0 == 'ld' and o0[0] == 'a' and len(output) > 2: + if OPT25 and \ + (i1 in ('cp', 'or', 'and') and o1[0] == 'h' or + i1 in ('sub', 'add', 'sbc', 'adc') and o1[1] == 'h') \ + and i0 == 'ld' and o0[0] == 'a' and len(output) > 2: ii = inst(output[-3]) oo = oper(output[-3]) if ii == 'ld' and oo[0] == 'h' and oo[1] != 'a': @@ -2677,6 +2682,31 @@ def output_join(output, new_chunk): changed = True continue + # Converts: + # cp 0 + # Into: + # or a + if OPT29 and i1 == 'cp' and o1[0] == '0': + output[-1] = 'or a' + changed = True + continue + + # Converts: + # or/and X + # jp c/nc XXX + # Into: + # /jp XXX + if OPT30 and i1 in ('and', 'or') and i2 == 'jp': + c = condition(new_chunk[0]) + if c in ('c', 'nc'): + output.pop() + if c == 'nc': + new_chunk[0] = 'jp {0}'.format(o2[0]) + else: + new_chunk.pop(0) + changed = True + continue + changed, new_chunk = optiblock(new_chunk) output.extend(new_chunk) From 67a7cbd1c99e8d3fe0505fc10e1a82d842b9d5d8 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 18 Feb 2018 23:53:31 +0100 Subject: [PATCH 179/247] tests updated to reflect changes --- tests/functional/endif.asm | 4 +- tests/functional/fornextopt2.asm | 3 +- tests/functional/ifcoendif2.asm | 3 +- tests/functional/ifthencosntcoendif.asm | 4 +- tests/functional/ifthenlblsntcoendif.asm | 4 +- tests/functional/ifthensntcoelselblco.asm | 4 +- tests/functional/ifthensntcoelselblcoco.asm | 4 +- tests/functional/ifthensntcoendif.asm | 4 +- tests/functional/opt2_ifband.asm | 43 +++++++++++++++++++++ tests/functional/opt2_ifband.bas | 5 +++ tests/functional/opt2_ifbor.asm | 43 +++++++++++++++++++++ tests/functional/opt2_ifbor.bas | 5 +++ tests/functional/opt2_incdec_byte.asm | 41 ++++++++++++++++++++ tests/functional/opt2_incdec_byte.bas | 5 +++ tests/functional/opt3_einar.asm | 6 +-- tests/functional/opt3_lcd_o3_crash.asm | 4 +- 16 files changed, 154 insertions(+), 28 deletions(-) create mode 100644 tests/functional/opt2_ifband.asm create mode 100644 tests/functional/opt2_ifband.bas create mode 100644 tests/functional/opt2_ifbor.asm create mode 100644 tests/functional/opt2_ifbor.bas create mode 100644 tests/functional/opt2_incdec_byte.asm create mode 100644 tests/functional/opt2_incdec_byte.bas diff --git a/tests/functional/endif.asm b/tests/functional/endif.asm index 98014556c..67acc7144 100644 --- a/tests/functional/endif.asm +++ b/tests/functional/endif.asm @@ -10,10 +10,8 @@ __START_PROGRAM: add hl, sp ld (__CALL_BACK__), hl ei - ld h, 0 ld a, (_a) - cp h - jp nc, __LABEL1 + jp __LABEL1 ld hl, _a inc (hl) __LABEL1: diff --git a/tests/functional/fornextopt2.asm b/tests/functional/fornextopt2.asm index d121c888d..8dfe7cad4 100644 --- a/tests/functional/fornextopt2.asm +++ b/tests/functional/fornextopt2.asm @@ -21,9 +21,8 @@ __LABEL4: ld hl, _a dec (hl) __LABEL0: - ld h, 11 ld a, (_a) - cp h + cp 11 jp nc, __LABEL3 __LABEL2: jp __LABEL__lbl diff --git a/tests/functional/ifcoendif2.asm b/tests/functional/ifcoendif2.asm index 3ce344591..3767e61c6 100644 --- a/tests/functional/ifcoendif2.asm +++ b/tests/functional/ifcoendif2.asm @@ -10,9 +10,8 @@ __START_PROGRAM: add hl, sp ld (__CALL_BACK__), hl ei - ld h, 1 ld a, (_a) - cp h + cp 1 jp nc, __LABEL1 ld hl, _a inc (hl) diff --git a/tests/functional/ifthencosntcoendif.asm b/tests/functional/ifthencosntcoendif.asm index 98014556c..67acc7144 100644 --- a/tests/functional/ifthencosntcoendif.asm +++ b/tests/functional/ifthencosntcoendif.asm @@ -10,10 +10,8 @@ __START_PROGRAM: add hl, sp ld (__CALL_BACK__), hl ei - ld h, 0 ld a, (_a) - cp h - jp nc, __LABEL1 + jp __LABEL1 ld hl, _a inc (hl) __LABEL1: diff --git a/tests/functional/ifthenlblsntcoendif.asm b/tests/functional/ifthenlblsntcoendif.asm index f75b84ac5..93c1bac35 100644 --- a/tests/functional/ifthenlblsntcoendif.asm +++ b/tests/functional/ifthenlblsntcoendif.asm @@ -10,10 +10,8 @@ __START_PROGRAM: add hl, sp ld (__CALL_BACK__), hl ei - ld h, 0 ld a, (_a) - cp h - jp nc, __LABEL1 + jp __LABEL1 __LABEL__10: ld hl, _a inc (hl) diff --git a/tests/functional/ifthensntcoelselblco.asm b/tests/functional/ifthensntcoelselblco.asm index 42d7259a2..16eff1818 100644 --- a/tests/functional/ifthensntcoelselblco.asm +++ b/tests/functional/ifthensntcoelselblco.asm @@ -10,10 +10,8 @@ __START_PROGRAM: add hl, sp ld (__CALL_BACK__), hl ei - ld h, 0 ld a, (_a) - cp h - jp nc, __LABEL0 + jp __LABEL0 __LABEL__10: ld hl, _a inc (hl) diff --git a/tests/functional/ifthensntcoelselblcoco.asm b/tests/functional/ifthensntcoelselblcoco.asm index 42d7259a2..16eff1818 100644 --- a/tests/functional/ifthensntcoelselblcoco.asm +++ b/tests/functional/ifthensntcoelselblcoco.asm @@ -10,10 +10,8 @@ __START_PROGRAM: add hl, sp ld (__CALL_BACK__), hl ei - ld h, 0 ld a, (_a) - cp h - jp nc, __LABEL0 + jp __LABEL0 __LABEL__10: ld hl, _a inc (hl) diff --git a/tests/functional/ifthensntcoendif.asm b/tests/functional/ifthensntcoendif.asm index 98014556c..67acc7144 100644 --- a/tests/functional/ifthensntcoendif.asm +++ b/tests/functional/ifthensntcoendif.asm @@ -10,10 +10,8 @@ __START_PROGRAM: add hl, sp ld (__CALL_BACK__), hl ei - ld h, 0 ld a, (_a) - cp h - jp nc, __LABEL1 + jp __LABEL1 ld hl, _a inc (hl) __LABEL1: diff --git a/tests/functional/opt2_ifband.asm b/tests/functional/opt2_ifband.asm new file mode 100644 index 000000000..03fef6ec3 --- /dev/null +++ b/tests/functional/opt2_ifband.asm @@ -0,0 +1,43 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld a, (_a) + and 1 + jp z, __LABEL1 + ld hl, _a + inc (hl) +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + pop iy + pop ix + exx + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/opt2_ifband.bas b/tests/functional/opt2_ifband.bas new file mode 100644 index 000000000..5ff40202f --- /dev/null +++ b/tests/functional/opt2_ifband.bas @@ -0,0 +1,5 @@ + +DIM a as Ubyte + +IF a bAND 1 a = a + 1 + diff --git a/tests/functional/opt2_ifbor.asm b/tests/functional/opt2_ifbor.asm new file mode 100644 index 000000000..c6a3612f4 --- /dev/null +++ b/tests/functional/opt2_ifbor.asm @@ -0,0 +1,43 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld a, (_a) + or 1 + jp z, __LABEL1 + ld hl, _a + inc (hl) +__LABEL1: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + pop iy + pop ix + exx + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/opt2_ifbor.bas b/tests/functional/opt2_ifbor.bas new file mode 100644 index 000000000..87bc44604 --- /dev/null +++ b/tests/functional/opt2_ifbor.bas @@ -0,0 +1,5 @@ + +DIM a as Ubyte + +IF a bOR 1 a = a + 1 + diff --git a/tests/functional/opt2_incdec_byte.asm b/tests/functional/opt2_incdec_byte.asm new file mode 100644 index 000000000..3653f0111 --- /dev/null +++ b/tests/functional/opt2_incdec_byte.asm @@ -0,0 +1,41 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, _a + inc (hl) + ld hl, _a + dec (hl) + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + pop iy + pop ix + exx + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/opt2_incdec_byte.bas b/tests/functional/opt2_incdec_byte.bas new file mode 100644 index 000000000..9bce4d4e0 --- /dev/null +++ b/tests/functional/opt2_incdec_byte.bas @@ -0,0 +1,5 @@ +DIM a as UByte + +a = a + 1 +a = a - 1 + diff --git a/tests/functional/opt3_einar.asm b/tests/functional/opt3_einar.asm index 5b26b212b..4883b26b3 100644 --- a/tests/functional/opt3_einar.asm +++ b/tests/functional/opt3_einar.asm @@ -37,9 +37,9 @@ _x2: push hl inc sp ld (ix-1), 129 - ld a, (ix-1) - neg - add a, 32 + ld a, 32 + sub (ix-1) + ccf jp nc, __LABEL0 ld hl, __LABEL2 xor a diff --git a/tests/functional/opt3_lcd_o3_crash.asm b/tests/functional/opt3_lcd_o3_crash.asm index fc23583f1..5d2c2dc83 100644 --- a/tests/functional/opt3_lcd_o3_crash.asm +++ b/tests/functional/opt3_lcd_o3_crash.asm @@ -41,10 +41,8 @@ _Drawscreen: __LABEL3: inc (ix-1) __LABEL0: - ld a, (ix-1) - ld h, a ld a, 21 - cp h + cp (ix-1) jp nc, __LABEL3 _Drawscreen__leave: ld sp, ix From a62b17168bbc0fc791c1bf086335bad2debfc22f Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Thu, 1 Mar 2018 22:52:24 +0100 Subject: [PATCH 180/247] add O3 further optimizations --- arch/zx48k/optimizer.py | 11 ++++++-- tests/functional/opt3_haplo06.asm | 43 +++++++++++++++++++++++++++++++ tests/functional/opt3_haplo06.bas | 8 ++++++ 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 tests/functional/opt3_haplo06.asm create mode 100644 tests/functional/opt3_haplo06.bas diff --git a/arch/zx48k/optimizer.py b/arch/zx48k/optimizer.py index b49d2d246..98bd41f02 100644 --- a/arch/zx48k/optimizer.py +++ b/arch/zx48k/optimizer.py @@ -81,6 +81,7 @@ OPT24 = True OPT25 = True OPT26 = True +OPT27 = True RAND_COUNT = 0 @@ -2006,13 +2007,19 @@ def optimize(self): if changed: break - if OPT26 and i1 == i2 == 'ld' and (o1[0], o1[1], o2[0], o2[1]) == ('d', 'h', 'e', 'l') and not \ - self.is_used(['h', 'l'], i + 2): + if OPT26 and i1 == i2 == 'ld' and (o1[0], o1[1], o2[0], o2[1]) == ('d', 'h', 'e', 'l') and \ + not self.is_used(['h', 'l'], i + 2): self[i] = 'ex de, hl' self.pop(i + 1) changed = True break + if OPT27 and i1 in ('cp', 'or', 'and', 'add', 'adc', 'sub', 'sbc') and o1[-1] != 'a' and \ + not self.is_used(o1[-1], i + 1) and i0 == 'ld' and o0[0] == o1[-1] and \ + (o0[1] == '(hl)' or RE_IXIND.match(o0[1])): + self[i] = '{0} {1}'.format(i1, o0[1]) + self.pop(i - 1) + regs.op(i1, o1) diff --git a/tests/functional/opt3_haplo06.asm b/tests/functional/opt3_haplo06.asm new file mode 100644 index 000000000..22c9a5b0e --- /dev/null +++ b/tests/functional/opt3_haplo06.asm @@ -0,0 +1,43 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, (_y) + ld a, (_a) + or (hl) + inc hl + or (hl) + ld (_a), a + ld bc, 0 +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + pop iy + pop ix + exx + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 +_y: + DEFB 00, 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/opt3_haplo06.bas b/tests/functional/opt3_haplo06.bas new file mode 100644 index 000000000..0d50974da --- /dev/null +++ b/tests/functional/opt3_haplo06.bas @@ -0,0 +1,8 @@ + +DIM a as UByte +DIM y as Uinteger + +a = a bOR peek(y) bOR peek(y + 1) + + + From f4c33a14a93ea26a546e8199a2a045edc1ac8423 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 6 Mar 2018 23:30:50 +0100 Subject: [PATCH 181/247] optimize O3 level of the peephole This optimization removes anything after an uncondional jump if it is not a label. --- arch/zx48k/backend/__init__.py | 11 ++++++ tests/functional/doloop4.asm | 3 -- tests/functional/endif.asm | 2 -- tests/functional/fornextopt.asm | 3 -- tests/functional/fornextopt2.asm | 3 -- tests/functional/ifemptylabel1.asm | 3 -- tests/functional/ifemptylabel2.asm | 3 -- tests/functional/ifthencosntcoendif.asm | 2 -- tests/functional/ifthensntcoendif.asm | 2 -- tests/functional/opt3_ifgotoelse.asm | 46 +++++++++++++++++++++++++ tests/functional/opt3_ifgotoelse.bas | 11 ++++++ tests/functional/opt3_lcd5.asm | 8 ++--- tests/functional/while.asm | 8 ++--- tests/functional/whilefalse1.asm | 3 -- 14 files changed, 73 insertions(+), 35 deletions(-) create mode 100644 tests/functional/opt3_ifgotoelse.asm create mode 100644 tests/functional/opt3_ifgotoelse.bas diff --git a/arch/zx48k/backend/__init__.py b/arch/zx48k/backend/__init__.py index c3b5f4911..c75be5b5e 100644 --- a/arch/zx48k/backend/__init__.py +++ b/arch/zx48k/backend/__init__.py @@ -128,6 +128,7 @@ OPT28 = True OPT29 = True OPT30 = True +OPT31 = True # Label RegExp RE_LABEL = re.compile('^[ \t]*[a-zA-Z_][_a-zA-Z\d]*:') @@ -2707,6 +2708,16 @@ def output_join(output, new_chunk): changed = True continue + # Converts + # jp XXX + # + # Into: + # jp XXX + if OPT31 and i1 == 'jp' and not condition(output[-1]) and i2 is not None and i2[-1] != ':': + new_chunk.pop(0) + changed = True + continue + changed, new_chunk = optiblock(new_chunk) output.extend(new_chunk) diff --git a/tests/functional/doloop4.asm b/tests/functional/doloop4.asm index 9beded5f0..dd15f3a3b 100644 --- a/tests/functional/doloop4.asm +++ b/tests/functional/doloop4.asm @@ -16,9 +16,6 @@ __LABEL__20: jp __LABEL0 __LABEL1: jp __LABEL__20 - ld hl, 0 - ld b, h - ld c, l __END_PROGRAM: di ld hl, (__CALL_BACK__) diff --git a/tests/functional/endif.asm b/tests/functional/endif.asm index 67acc7144..2759c7538 100644 --- a/tests/functional/endif.asm +++ b/tests/functional/endif.asm @@ -12,8 +12,6 @@ __START_PROGRAM: ei ld a, (_a) jp __LABEL1 - ld hl, _a - inc (hl) __LABEL1: ld hl, 0 ld b, h diff --git a/tests/functional/fornextopt.asm b/tests/functional/fornextopt.asm index 1fd16a021..9b0fb0bcd 100644 --- a/tests/functional/fornextopt.asm +++ b/tests/functional/fornextopt.asm @@ -27,9 +27,6 @@ __LABEL0: jp nc, __LABEL3 __LABEL2: jp __LABEL__lbl - ld hl, 0 - ld b, h - ld c, l __END_PROGRAM: di ld hl, (__CALL_BACK__) diff --git a/tests/functional/fornextopt2.asm b/tests/functional/fornextopt2.asm index 8dfe7cad4..7bebdf5c6 100644 --- a/tests/functional/fornextopt2.asm +++ b/tests/functional/fornextopt2.asm @@ -26,9 +26,6 @@ __LABEL0: jp nc, __LABEL3 __LABEL2: jp __LABEL__lbl - ld hl, 0 - ld b, h - ld c, l __END_PROGRAM: di ld hl, (__CALL_BACK__) diff --git a/tests/functional/ifemptylabel1.asm b/tests/functional/ifemptylabel1.asm index e797ba471..bac7b2391 100644 --- a/tests/functional/ifemptylabel1.asm +++ b/tests/functional/ifemptylabel1.asm @@ -16,9 +16,6 @@ __LABEL__Here: inc (hl) __LABEL1: jp __LABEL__Here - ld hl, 0 - ld b, h - ld c, l __END_PROGRAM: di ld hl, (__CALL_BACK__) diff --git a/tests/functional/ifemptylabel2.asm b/tests/functional/ifemptylabel2.asm index 7b3378bf2..3744bd571 100644 --- a/tests/functional/ifemptylabel2.asm +++ b/tests/functional/ifemptylabel2.asm @@ -20,9 +20,6 @@ __LABEL__Here: ld (_a), a __LABEL1: jp __LABEL__Here - ld hl, 0 - ld b, h - ld c, l __END_PROGRAM: di ld hl, (__CALL_BACK__) diff --git a/tests/functional/ifthencosntcoendif.asm b/tests/functional/ifthencosntcoendif.asm index 67acc7144..2759c7538 100644 --- a/tests/functional/ifthencosntcoendif.asm +++ b/tests/functional/ifthencosntcoendif.asm @@ -12,8 +12,6 @@ __START_PROGRAM: ei ld a, (_a) jp __LABEL1 - ld hl, _a - inc (hl) __LABEL1: ld hl, 0 ld b, h diff --git a/tests/functional/ifthensntcoendif.asm b/tests/functional/ifthensntcoendif.asm index 67acc7144..2759c7538 100644 --- a/tests/functional/ifthensntcoendif.asm +++ b/tests/functional/ifthensntcoendif.asm @@ -12,8 +12,6 @@ __START_PROGRAM: ei ld a, (_a) jp __LABEL1 - ld hl, _a - inc (hl) __LABEL1: ld hl, 0 ld b, h diff --git a/tests/functional/opt3_ifgotoelse.asm b/tests/functional/opt3_ifgotoelse.asm new file mode 100644 index 000000000..8588e538a --- /dev/null +++ b/tests/functional/opt3_ifgotoelse.asm @@ -0,0 +1,46 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld a, (_a) + dec a + jp nz, __LABEL0 + ld hl, _a + inc (hl) + jp __LABEL__10 +__LABEL0: + ld a, (_a) + add a, 2 + ld (_a), a +__LABEL__10: + ld bc, 0 +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + pop iy + pop ix + exx + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/opt3_ifgotoelse.bas b/tests/functional/opt3_ifgotoelse.bas new file mode 100644 index 000000000..f92630f4b --- /dev/null +++ b/tests/functional/opt3_ifgotoelse.bas @@ -0,0 +1,11 @@ +DIM a as Ubyte + +IF a = 1 THEN + a = a + 1 + GOTO 10 +ELSE + a = a + 2 + GOTO 10 +END IF + +10 REM diff --git a/tests/functional/opt3_lcd5.asm b/tests/functional/opt3_lcd5.asm index aefa3dd44..ea70741b8 100644 --- a/tests/functional/opt3_lcd5.asm +++ b/tests/functional/opt3_lcd5.asm @@ -120,10 +120,8 @@ __LABEL8: ld a, (hl) and (ix+9) jp _ScanField__leave - jp __LABEL1 __LABEL0: xor a -__LABEL1: _ScanField__leave: ld sp, ix pop ix @@ -483,7 +481,7 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A ld a, l ret -#line 365 "opt3_lcd5.bas" +#line 363 "opt3_lcd5.bas" #line 1 "lei16.asm" __LEI16: @@ -502,7 +500,7 @@ checkParity: inc a ; True ret ENDP -#line 366 "opt3_lcd5.bas" +#line 364 "opt3_lcd5.bas" #line 1 "lti16.asm" #line 1 "lei8.asm" @@ -545,7 +543,7 @@ checkParity: inc a ; True ret ENDP -#line 367 "opt3_lcd5.bas" +#line 365 "opt3_lcd5.bas" ZXBASIC_USER_DATA: _x: diff --git a/tests/functional/while.asm b/tests/functional/while.asm index 9f9f47e66..dc9efd8e7 100644 --- a/tests/functional/while.asm +++ b/tests/functional/while.asm @@ -37,10 +37,6 @@ __LABEL__40: jp __LABEL2 __LABEL3: jp __LABEL__20 - jp __LABEL__40 - ld hl, 0 - ld b, h - ld c, l __END_PROGRAM: di ld hl, (__CALL_BACK__) @@ -330,7 +326,7 @@ __LTF: ; A < B call __FPSTACK_POP jp __FTOU8 ; Convert to 8 bits -#line 46 "while.bas" +#line 42 "while.bas" #line 1 "pushf.asm" @@ -361,7 +357,7 @@ __FP_PUSH_REV: ret -#line 47 "while.bas" +#line 43 "while.bas" ZXBASIC_USER_DATA: _a: diff --git a/tests/functional/whilefalse1.asm b/tests/functional/whilefalse1.asm index 864cacbff..9025396e5 100644 --- a/tests/functional/whilefalse1.asm +++ b/tests/functional/whilefalse1.asm @@ -18,9 +18,6 @@ __LABEL__BAD: jp __LABEL0 __LABEL1: jp __LABEL__BAD - ld hl, 0 - ld b, h - ld c, l __END_PROGRAM: di ld hl, (__CALL_BACK__) From c01d28c5aaf6c0241ef6e78855c639cfec8debf3 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Thu, 1 Mar 2018 23:21:49 +0100 Subject: [PATCH 182/247] bugfix: print42 now works with CHR(13) and CHR(22) CHR$(13) (nuewline) wasn't being handled correctly. Fixed. CHR$(22) (at) wasn't supported either. Now it is: CHR(22, y, x) does AT y, x Also adds support for chr$(8) (\r or del) This allows to move the cursor 1 position "back" Finally it redefines character "_" in PRINT42 This is needed since it has one extra bit which should not be printed. --- library/print42.bas | 224 +++++++++++++++++++---------------- tests/functional/print42.asm | 56 ++++++--- 2 files changed, 167 insertions(+), 113 deletions(-) diff --git a/library/print42.bas b/library/print42.bas index 58eea735d..bbe8ba44c 100644 --- a/library/print42.bas +++ b/library/print42.bas @@ -24,7 +24,7 @@ asm LD A, H OR L - RET Z + JP Z, print42end LD C,(HL) INC HL @@ -32,7 +32,7 @@ asm LD A, C OR B - JP Z, print64end ; Is the length of the string 0? If so, quit. + JP Z, print42end ; Is the length of the string 0? If so, quit. INC HL ;Puts HL to the first real character in the string. @@ -48,14 +48,13 @@ examineChar: LOCAL isAt isAt: EX DE,HL ; Get DE to hold HL for a moment - ;;AND A ; Plays with the flags. One of the things it does is reset Carry. + ;;AND A ; Plays with the flags. One of the things it does is reset Carry. ;;LD HL,00002 - ;;SBC HL,BC ; Subtract length of string from HL. + ;;SBC HL,BC ; Subtract length of string from HL. LD HL, -2 ADD HL, BC EX DE,HL ; Get HL back from DE - ;;RET NC ; If the result WASN'T negative, return. (We need AT to have parameters to make sense) - JP NC, print64end ; If the result WASN'T negative, return. (We need AT to have parameters to make sense) + JP NC, print42end ; If the result WASN'T negative, return. (We need AT to have parameters to make sense) INC HL ; Onto our Y co-ordinate LD D,(HL) ; Put it in D @@ -63,32 +62,50 @@ isAt: INC HL ; Onto our X co-ordinate LD E,(HL) ; Put the next one in E DEC BC ; and move our string remaining counter down one - CALL nxtchar ; Call routine to shuffle right a char - JR newline ; Hop over to + ld (xycoords), de + JR nextChar LOCAL isNewline isNewline: CP 13 ; Is this character a newline? - JR NZ,checkvalid ; If not, jump forward + JR NZ, checkdel ; If not, jump forward LOCAL newline newline: - ;LD DE,(63536) + ld de, (xycoords) CALL nxtline ; move to next line + ld (xycoords), de + JR nextChar - ;LD (63536),DE ; and go on to next character +LOCAL checkdel +checkdel: + CP 8 + JR NZ, checkvalid + ld de, (xycoords) + dec de + ld (xycoords), de + ld a, 41 + cp e + JR NC, nextChar + ld e, a + ld (xycoords), de + ld a, 23 + cp d + JR NC, nextChar + ld d, a + ld (xycoords), de JR nextChar LOCAL checkvalid checkvalid: - CP 31 ; Is character <31? - JR C, nextChar ; If not go to next character + CP 31 ; Is character <31? + JR C, nextChar ; If not go to next character LOCAL prn prn: PUSH HL ; Save our position PUSH BC ; Save our countdown of chars left - CALL printachar ; Go print a character + CALL printachar ; Go print a character POP BC ; Recover our count POP HL ; Recover our position @@ -97,14 +114,14 @@ nextChar: INC HL ; Move to the next position DEC BC ; count off a character LD A,B - OR C ; Did we hit the end of our string? (BC=0?) + OR C ; Did we hit the end of our string? (BC=0?) JR NZ, examineChar ; If not, we need to go look at the next character. - JP print64end ; End the print routine + JP print42end ; End the print routine ; This routine forms the new 6-bit wide characters and -;alters the colours to match the text. The y,x co-ordinates and eight -;bytes of workspace are located at the end of this chunk. +; alters the colours to match the text. The y,x co-ordinates and eight +; bytes of workspace are located at the end of this chunk. ; it starts with the character ascii code in the accumulator LOCAL printachar @@ -120,8 +137,8 @@ printachar: ld de, whichcolumn-32 ; the character is at least 32, so space = 0th entry. add hl, de ; HL -> table entry for char. ld a, (hl) ; Load our column slice data from the table. - cp 32 ; Is it less than 32? - jr nc, calcChar ; If so, go to the calculated character subroutine + cp 32 ; Is it less than 32? + jr nc, calcChar ; If so, go to the calculated character subroutine ; This is the special case 'we defined the character in the table' option ld de, characters ; Point DE at our table @@ -129,16 +146,16 @@ printachar: call mult8 ; multiplies L by 8 and adds in DE [so HL points at our table entry] ld b, h ld c, l ; Copy our character data address into BC - jr printdata ; We have our data source, so we print it. + jr printdata ; We have our data source, so we print it. LOCAL calcChar calcChar: ; this is the calculate from the ROM data option ; a holds the column kill data - ld de, 15360 ; Character set-256. We could use CHARS here, maybe; but might not work with a redefiend character set. + ld de, 15360 ; Character set-256. We could use CHARS here, maybe; but might not work with a redefiend character set. ld l, c ; Get our character back from C call mult8 ; Multiply l by 8 and add to DE. (HL points at the ROM data for our character now) - ld de, workspace ; Point DE at our 8 byte workspace. + ld de, workspace ; Point DE at our 8 byte workspace. push de ; Save it exx ; ld c, a ; Put our kill column in C' @@ -150,21 +167,21 @@ calcChar: ; this is the calculate from the ROM data option LOCAL loop1 loop1: ld a, (hl) ; Load a byte of character data - inc hl ; point at the next byte + inc hl ; point at the next byte exx ; ld e, a ; Put it in e' - and c ; keep the left column block we're using + and c ; keep the left column block we're using ld d, a ; and put it in d' ld a, e ; grab our original back rla ; shift it left (which pushes out our unwanted column) - and b ; keep just the right block - or d ; mix with the left block + and b ; keep just the right block + or d ; mix with the left block exx ; ld (de), a ; put it into our workspace - inc de ; next workspace byte + inc de ; next workspace byte djnz loop1 ; go round for our other bytes - pop bc ; Recover a pointer to our workspace. + pop bc ; Recover a pointer to our workspace. LOCAL printdata printdata: @@ -259,18 +276,18 @@ hop3: and d or b ld (hl), a ; Write out our byte - inc hl ; Go one byte right + inc hl ; Go one byte right ld a, (hl) ; Bring it in and e - or c ; mix those leftover bits into the next block + or c ; mix those leftover bits into the next block ld (hl), a ; Write it out again pop hl - inc h ; Next line + inc h ; Next line exx - inc bc ; Next workspace byte + inc bc ; Next workspace byte pop af dec a - jr nz, hop4 ; And go back! + jr nz, hop4 ; And go back! exx ; Tidy up pop hl ; Clear stack leftovers @@ -292,20 +309,20 @@ testcoords: LOCAL nxtchar nxtchar: - ld a, e ; - cp 42 ; Are we >42? - jr c, ycoord ; if not, hop forward + ld a, e + cp 42 ; Are we >42? + jr c, ycoord ; if not, hop forward LOCAL nxtline nxtline: - inc d ; if so, so bump us to the next line down + inc d ; if so, so bump us to the next line down ld e, 0 ; and reset x to left edge LOCAL ycoord ycoord: - ld a, d ; - cp 24 ; are we >24 lines? - ret c ; if no, exit subroutine + ld a, d + cp 24 ; are we >24 lines? + ret c ; if no, exit subroutine ld d, 0 ; if yes, wrap around to top line again. ret ; exit subroutine end asm @@ -313,8 +330,8 @@ printAt42Coords: asm LOCAL xycoords xycoords: - defb 0 ; x coordinate - defb 0 ; y coordinate + defb 0 ; x coordinate + defb 0 ; y coordinate LOCAL workspace workspace: @@ -334,29 +351,29 @@ workspace: LOCAL whichcolumn whichcolumn: - defb 254 ; SPACE - defb 254 ; ! - defb 128 ; "" - defb 224 ; # - defb 128 ; $ - defb 0 ; % (Redefined below) - defb 1 ; & (Redefined below) - defb 128 ; ' - defb 128 ; ( - defb 128 ; ) - defb 128 ; * - defb 128 ; + - defb 128 ; , - defb 128 ; - - defb 128 ; . - defb 128 ; / - defb 2 ; 0 (Redefined below) + defb 254 ; SPACE + defb 254 ; ! + defb 128 ; "" + defb 224 ; # + defb 128 ; $ + defb 0 ; % (Redefined below) + defb 1 ; & (Redefined below) + defb 128 ; ' + defb 128 ; ( + defb 128 ; ) + defb 128 ; * + defb 128 ; + + defb 128 ; , + defb 128 ; - + defb 128 ; . + defb 128 ; / + defb 2 ; 0 (Redefined below) defb 128 ; 1 defb 224 ; 2 defb 224 ; 3 defb 252 ; 4 - defb 224 ; 5 - defb 224 ; 6 + defb 224 ; 5 + defb 224 ; 6 defb 192 ; 7 defb 240 ; 8 defb 240 ; 9 @@ -395,40 +412,40 @@ whichcolumn: defb 252 ; Z defb 224 ; [ defb 252 ; \ - defb 240 ; ] - defb 252 ; ^ - defb 240 ; _ - defb 240 ; UK Pound (Currency) Symbol - defb 255 ; a - defb 128 ; b - defb 255 ; c - defb 255 ; d - defb 255 ; e - defb 255 ; f - defb 255 ; g - defb 255 ; h - defb 255 ; i - defb 255 ; j - defb 255 ; k - defb 255 ; l - defb 255 ; m - defb 255 ; n - defb 255 ; o - defb 255 ; p - defb 255 ; q - defb 255 ; r - defb 255 ; s - defb 255 ; t - defb 255 ; u - defb 255 ; v - defb 255 ; w - defb 255 ; x - defb 255 ; y - defb 255 ; z - defb 128 ; { - defb 128 ; | - defb 255 ; } - defb 128 ; ~ + defb 240 ; ] + defb 252 ; ^ + defb 6 ; _ + defb 240 ; UK Pound (Currency) Symbol + defb 255 ; a + defb 128 ; b + defb 255 ; c + defb 255 ; d + defb 255 ; e + defb 255 ; f + defb 255 ; g + defb 255 ; h + defb 255 ; i + defb 255 ; j + defb 255 ; k + defb 255 ; l + defb 255 ; m + defb 255 ; n + defb 255 ; o + defb 255 ; p + defb 255 ; q + defb 255 ; r + defb 255 ; s + defb 255 ; t + defb 255 ; u + defb 255 ; v + defb 255 ; w + defb 255 ; x + defb 255 ; y + defb 255 ; z + defb 128 ; { + defb 128 ; | + defb 255 ; } + defb 128 ; ~ defb 5 ; (c) end column data @@ -486,10 +503,19 @@ characters: defb 164 defb 180 defb 72 - defb 48 + defb 48 + + defb 0 + defb 0 + defb 0 + defb 0 + defb 0 + defb 0 + defb 0 + defb 0xFC -LOCAL print64end -print64end: +LOCAL print42end +print42end: ENDP end asm diff --git a/tests/functional/print42.asm b/tests/functional/print42.asm index 2416bad1e..f44c50e50 100644 --- a/tests/functional/print42.asm +++ b/tests/functional/print42.asm @@ -54,13 +54,13 @@ _print42: PROC LD A, H OR L - RET Z + JP Z, print42end LD C,(HL) INC HL LD B,(HL) LD A, C OR B - JP Z, print64end + JP Z, print42end INC HL LOCAL examineChar examineChar: @@ -75,22 +75,42 @@ isAt: LD HL, -2 ADD HL, BC EX DE,HL - JP NC, print64end + JP NC, print42end INC HL LD D,(HL) DEC BC INC HL LD E,(HL) DEC BC - CALL nxtchar - JR newline + ld (xycoords), de + JR nextChar LOCAL isNewline isNewline: CP 13 - JR NZ,checkvalid + JR NZ, checkdel LOCAL newline newline: + ld de, (xycoords) CALL nxtline + ld (xycoords), de + JR nextChar + LOCAL checkdel +checkdel: + CP 8 + JR NZ, checkvalid + ld de, (xycoords) + dec de + ld (xycoords), de + ld a, 41 + cp e + JR NC, nextChar + ld e, a + ld (xycoords), de + ld a, 23 + cp d + JR NC, nextChar + ld d, a + ld (xycoords), de JR nextChar LOCAL checkvalid checkvalid: @@ -110,7 +130,7 @@ nextChar: LD A,B OR C JR NZ, examineChar - JP print64end + JP print42end LOCAL printachar printachar: EXX @@ -287,9 +307,9 @@ ycoord: ret c ld d, 0 ret -#line 257 +#line 277 __LABEL__printAt42Coords: -#line 312 +#line 329 LOCAL xycoords xycoords: defb 0 @@ -369,7 +389,7 @@ whichcolumn: defb 252 defb 240 defb 252 - defb 240 + defb 6 defb 240 defb 255 defb 128 @@ -452,10 +472,18 @@ characters: defb 180 defb 72 defb 48 - LOCAL print64end -print64end: + defb 0 + defb 0 + defb 0 + defb 0 + defb 0 + defb 0 + defb 0 + defb 0xFC + LOCAL print42end +print42end: ENDP -#line 477 +#line 502 _print42__leave: ex af, af' exx @@ -789,7 +817,7 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ENDP -#line 460 "print42.bas" +#line 488 "print42.bas" ZXBASIC_USER_DATA: ZXBASIC_MEM_HEAP: From e0da1a13133591e989debe72e4af3a531995bdcd Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 13 Mar 2018 20:57:26 +0100 Subject: [PATCH 183/247] Add input42 capability - Implements input42 like input.bas library does --- library/input42.bas | 91 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 library/input42.bas diff --git a/library/input42.bas b/library/input42.bas new file mode 100644 index 000000000..ba0fb340f --- /dev/null +++ b/library/input42.bas @@ -0,0 +1,91 @@ +' ---------------------------------------------------------------- +' This file is released under the MIT License +' +' Copyleft (k) 2008 +' by Jose Rodriguez-Rosa (a.k.a. Boriel) +' +' Simple INPUT routine (not as powerful as Sinclair BASIC's), but +' this one uses PRINT42 routine +' Usage: A$ = INPUT42(MaxChars) +' ---------------------------------------------------------------- +#ifndef __LIBRARY_INPUT42__ + +REM Avoid recursive / multiple inclusion + +#define __LIBRARY_INPUT42__ + +REM The input subroutine +REM DOES NOT act like ZX Spectrum INPUT command +REM Uses ZX SPECTRUM ROM + +#include once +#include once +#include once + +#pragma push(case_insensitive) +#pragma case_insensitive = True + +FUNCTION input42(MaxLen AS UINTEGER) AS STRING + DIM LastK AS UBYTE AT 23560: REM LAST_K System VAR + DIM result$ AS STRING + DIM i as UINTEGER + + result$ = "" + POKE 23611, PEEK 23611 bOR 8 + + DO + PRIVATEInputShowCursor42() + + REM Wait for a Key Press + LastK = 0 + DO LOOP UNTIL LastK <> 0 + + PRIVATEInputHideCursor42() + + IF LastK = 12 THEN + IF LEN(result$) THEN REM "Del" key code is 12 + IF LEN(result$) = 1 THEN + LET result$ = "" + ELSE + LET result$ = result$( TO LEN(result$) - 2) + END IF + PRINT42 CHR$(8) + END IF + ELSEIF LastK >= CODE(" ") AND LEN(result$) < MaxLen THEN + LET result$ = result$ + CHR$(LastK) + PRINT42 CHR$(LastK) + END IF + + LOOP UNTIL LastK = 13 : REM "Enter" key code is 13 + + FOR i = 1 TO LEN(result$): + PRINT42 CHR$(8) + " " + CHR$(8) + NEXT + + RETURN result$ + +END FUNCTION + +#pragma pop(case_insensitive) + +' ------------------------------------------------------------------ +' Function 'PRIVATE' to this module. +' Shows a flashing cursor +' ------------------------------------------------------------------ +SUB FASTCALL PRIVATEInputShowCursor42 + REM Print a Flashing cursor at current print position + OVER 1: PRINT42 "_" + CHR$(8): OVER 0 +END SUB + + +' ------------------------------------------------------------------ +' Function 'PRIVATE' to this module. +' Hides the flashing cursor +' ------------------------------------------------------------------ +SUB FASTCALL PRIVATEInputHideCursor42 + REM Print a Flashing cursor at current print position + OVER 0: PRINT42 " " + CHR$(8) +END SUB + +#endif + From b14635e11541beaf6277e938158dedf57023f770 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 13 Mar 2018 22:19:12 +0100 Subject: [PATCH 184/247] =?UTF-8?q?Bump=20version:=201.8.1=20=E2=86=92=201?= =?UTF-8?q?.8.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- ChangeLog | 6 ++++++ version.py | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index edecd43f2..7c4aa7312 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,4 +1,4 @@ [bumpversion] -current_version = 1.8.1 +current_version = 1.8.2 files = version.py diff --git a/ChangeLog b/ChangeLog index 6a7744c9c..e721053b1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,10 @@ ================================================================ +Changes from Version 1.8.1 to 1.8.2 +! Bugfixes in the peephole optimizer ++ Shorter and faster generated code (deep optimizations) +! Bugfix in the PRINT42 routine that now supports newlines, etc ++ Implemented routine input42 (INPUT42.BAS) for PRINT42 mode +================================================================ Changes from Version 1.8.0 to 1.8.1 ! Bugfixes in the peephole optimizer ! Bugfix in OUT instruction diff --git a/version.py b/version.py index 8e066ca35..7e7369239 100755 --- a/version.py +++ b/version.py @@ -1 +1 @@ -VERSION = '1.8.1' +VERSION = '1.8.2' From 4094630361766e380e0bb4bc94081cf6666e126b Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 20 Mar 2018 23:20:40 +0100 Subject: [PATCH 185/247] bugfix: crash on wrong parameters When intantiating an STRSLICE symbol with wrong arguments (their type must be numeric), the program crashed. It should just report semantic error and return None. Fixed. --- symbols/strslice.py | 4 ++++ tests/symbols/test_symbolSTRSLICE.py | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/symbols/strslice.py b/symbols/strslice.py index aa764ab8b..6bf0f902c 100644 --- a/symbols/strslice.py +++ b/symbols/strslice.py @@ -87,6 +87,10 @@ def make_node(cls, lineno, s, lower, upper): upper = TYPECAST.make_node(gl.SYMBOL_TABLE.basic_types[gl.STR_INDEX_TYPE], BINARY.make_node('MINUS', upper, base, lineno=lineno, func=lambda x, y: x - y), lineno) + + if lower is None or upper is None: + return None + if is_number(lower): lo = lower.value if lo < gl.MIN_STRSLICE_IDX: diff --git a/tests/symbols/test_symbolSTRSLICE.py b/tests/symbols/test_symbolSTRSLICE.py index c95fdec49..608038f08 100644 --- a/tests/symbols/test_symbolSTRSLICE.py +++ b/tests/symbols/test_symbolSTRSLICE.py @@ -55,6 +55,11 @@ def test_make_node(self): self.assertIsInstance(s, symbols.STRING) self.assertEqual(s.value, 'XB') + def test_make_node_wrong(self): + bad_index = symbols.VAR('a', 0, type_=gl.SYMBOL_TABLE.basic_types[gl.TYPE.string]) + s = symbols.STRSLICE.make_node(1, self.str_, bad_index, bad_index) + self.assertIsNone(s) + if __name__ == '__main__': unittest.main() From 2e7542942d0ac105e41bfe801b123312981e090a Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 20 Mar 2018 23:28:24 +0100 Subject: [PATCH 186/247] Add comment to function for better clarification is_numeric() checks for numerical types of all the subnodes. Numerical types are Byte, Ubyte, Integer, UInteger, Long, ULong, Fixed and Float. --- api/check.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/check.py b/api/check.py index b3a009091..79da537b5 100644 --- a/api/check.py +++ b/api/check.py @@ -340,6 +340,8 @@ def is_signed(*p): def is_numeric(*p): + """ Returns false unless all elements in p are of numerical type + """ from symbols.type_ import Type try: From 5c5b4f578825811cee42ef37847db677b37b036a Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 20 Mar 2018 23:31:24 +0100 Subject: [PATCH 187/247] bugfix: report undeclared function for f$(x$) Sometimes using f$(x) (with X undeclared) reported a different error message or event crash the compiler. Fixed. --- tests/functional/llb.bas | 4 ++++ tests/functional/test_errmsg.txt | 3 +++ zxbparser.py | 8 ++++---- 3 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 tests/functional/llb.bas diff --git a/tests/functional/llb.bas b/tests/functional/llb.bas new file mode 100644 index 000000000..5f0d7fbed --- /dev/null +++ b/tests/functional/llb.bas @@ -0,0 +1,4 @@ +DIM strTemp as String + +If f$(strTemp)="," then +End If diff --git a/tests/functional/test_errmsg.txt b/tests/functional/test_errmsg.txt index 36c765331..76aa808c8 100644 --- a/tests/functional/test_errmsg.txt +++ b/tests/functional/test_errmsg.txt @@ -113,3 +113,6 @@ atoloduplbl.asm:3: label '.SetSubScreen' already defined at line 2 >>> process_file('asmerror2.asm') asmerror2.asm:2: Error: illegal preprocessor character '@' asmerror2.asm:2: Syntax error. Unexpected end of line [NEWLINE] +>>> process_file('llb.bas') +llb.bas:3: Undeclared function "f$" + diff --git a/zxbparser.py b/zxbparser.py index abbc40279..2f7c1fcae 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -314,7 +314,7 @@ def make_call(id_, lineno, args): if entry is None: return None - if entry.class_ is CLASS.unknown and entry.type_ == TYPE.string and len(args) == 1: + if entry.class_ is CLASS.unknown and entry.type_ == TYPE.string and len(args) == 1 and is_numeric(args[0]): entry.class_ = CLASS.var # A scalar variable. e.g a$(expr) if entry.class_ == CLASS.array: # An already declared array @@ -339,8 +339,8 @@ def make_call(id_, lineno, args): return None if len(args) == 1: - return symbols.STRSLICE.make_node(lineno, entry, args[0].value, - args[0].value) + return symbols.STRSLICE.make_node(lineno, entry, args[0].value, args[0].value) + entry.accessed = True return entry @@ -2545,7 +2545,7 @@ def p_err_undefined_arr_access(p): def p_bexpr_func(p): """ bexpr : ID bexpr """ - args = make_arg_list(make_argument(p[2], p.lineno(0))) + args = make_arg_list(make_argument(p[2], p.lineno(2))) p[0] = make_call(p[1], p.lineno(1), args) if p[0] is None: return From 8ff7315afc729c3c1d0e4198f4f1c83cea30c035 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 21 Mar 2018 23:20:16 +0100 Subject: [PATCH 188/247] bugfix: fixes crash on undeclared subtr assign --- api/symboltable.py | 4 +- tests/functional/llc.asm | 808 +++++++++++++++++++++++++++++++++++++++ tests/functional/llc.bas | 1 + zxbparser.py | 3 + 4 files changed, 814 insertions(+), 2 deletions(-) create mode 100644 tests/functional/llc.asm create mode 100644 tests/functional/llc.bas diff --git a/api/symboltable.py b/api/symboltable.py index e59de8d4f..e3af34316 100644 --- a/api/symboltable.py +++ b/api/symboltable.py @@ -480,7 +480,7 @@ def access_func(self, id_, lineno, scope=None, default_type=None): return result - def access_call(self, id_, lineno, scope=None): + def access_call(self, id_, lineno, scope=None, type_=None): """ Creates a func/array/string call. Checks if id is callable or not. An identifier is "callable" if it can be followed by a list of para- meters. @@ -492,7 +492,7 @@ def access_call(self, id_, lineno, scope=None): - MyArray(5, 3.7, VAL("32")) makes MyArray identifier "callable". - MyString(5 TO 7) or MyString(5) is a "callable" string. """ - entry = self.access_id(id_, lineno, scope) + entry = self.access_id(id_, lineno, scope, default_type=type_) if entry is None: return self.access_func(id_, lineno) diff --git a/tests/functional/llc.asm b/tests/functional/llc.asm new file mode 100644 index 000000000..9dd8bbde6 --- /dev/null +++ b/tests/functional/llc.asm @@ -0,0 +1,808 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld hl, __LABEL0 + call __LOADSTR + push hl + xor a + push af + ld hl, 1 + push hl + ld hl, 1 + push hl + ld hl, (_r) + call __LETSUBSTR + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__LABEL0: + DEFW 0001h + DEFB 2Eh +#line 1 "letsubstr.asm" + + ; Substring assigment eg. LET a$(p0 TO p1) = "xxxx" + ; HL = Start of string + ; TOP of the stack -> p1 (16 bit, unsigned) + ; TOP -1 of the stack -> p0 register + ; TOP -2 Flag (popped out in A register) + ; A Register => 0 if HL is not freed from memory + ; => Not 0 if HL must be freed from memory on exit + ; TOP -3 B$ address + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 11 "letsubstr.asm" + +__LETSUBSTR: + PROC + + LOCAL __CONT0 + LOCAL __CONT1 + LOCAL __CONT2 + LOCAL __FREE_STR + LOCAL __FREE_STR0 + + exx + pop hl ; Return address + pop de ; p1 + pop bc ; p0 + exx + + pop af ; Flag + ex af, af' ; Save it for later + + pop de ; B$ + + exx + push hl ; push ret addr back + exx + + ld a, h + or l + jp z, __FREE_STR0 ; Return if null + + ld c, (hl) + inc hl + ld b, (hl) ; BC = Str length + inc hl ; HL = String start + push bc + + exx + ex de, hl + or a + sbc hl, bc ; HL = Length of string requester by user + inc hl ; len (a$(p0 TO p1)) = p1 - p0 + 1 + ex de, hl ; Saves it in DE + + pop hl ; HL = String length + exx + jp c, __FREE_STR0 ; Return if greather + exx ; Return if p0 > p1 + + or a + sbc hl, bc ; P0 >= String length? + exx + + jp z, __FREE_STR0 ; Return if equal + jp c, __FREE_STR0 ; Return if greather + + exx + add hl, bc ; Add it back + + sbc hl, de ; Length of substring > string => Truncate it + add hl, de ; add it back + jr nc, __CONT0 ; Length of substring within a$ + + ld d, h + ld e, l ; Truncate length of substring to fit within the strlen + +__CONT0: ; At this point DE = Length of subtring to copy + ; BC = start of char to copy + push de + + push bc + exx + pop bc + + add hl, bc ; Start address (within a$) so copy from b$ (in DE) + + push hl + exx + pop hl ; Start address (within a$) so copy from b$ (in DE) + + ld b, d ; Length of string + ld c, e + + ld (hl), ' ' + ld d, h + ld e, l + inc de + dec bc + ld a, b + or c + jr z, __CONT2 + + ; At this point HL = DE = Start of Write zone in a$ + ; BC = Number of chars to write + + ldir + +__CONT2: + + pop bc ; Recovers Length of string to copy + exx + ex de, hl ; HL = Source, DE = Target + + ld a, h + or l + jp z, __FREE_STR ; Return if B$ is NULL + + ld c, (hl) + inc hl + ld b, (hl) + inc hl + + ld a, b + or c + jp z, __FREE_STR ; Return if len(b$) = 0 + + ; Now if len(b$) < len(char to copy), copy only len(b$) chars + + push de + push hl + push bc + exx + pop hl ; LEN (b$) + or a + sbc hl, bc + add hl, bc + jr nc, __CONT1 + + ; If len(b$) < len(to copy) + ld b, h ; BC = len(to copy) + ld c, l + +__CONT1: + pop hl + pop de + ldir ; Copy b$ into a$(x to y) + + exx + ex de, hl + +__FREE_STR0: + ex de, hl + +__FREE_STR: + ex af, af' + or a ; If not 0, free + jp nz, __MEM_FREE + ret + + ENDP + +#line 32 "llc.bas" +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 69 "alloc.asm" + + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 33 "llc.bas" + +ZXBASIC_USER_DATA: +_r: + DEFB 00, 00 +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/llc.bas b/tests/functional/llc.bas new file mode 100644 index 000000000..82eaae45c --- /dev/null +++ b/tests/functional/llc.bas @@ -0,0 +1 @@ +LET r$(1)="." diff --git a/zxbparser.py b/zxbparser.py index 2f7c1fcae..7ea131e4c 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -1078,6 +1078,9 @@ def p_substr_assignment(p): # entry = SYMBOL_TABLE.get_id_entry(q[0]) return + if entry.class_ == CLASS.unknown: + entry.class_ = CLASS.var + assert entry.class_ == CLASS.var and entry.type_ == TYPE.string r = q[3] if r.type_ != TYPE.string: From ca35495d7c1cbfc9068eec954aa9c47b2aa324d1 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 31 Mar 2018 21:04:19 +0200 Subject: [PATCH 189/247] bugfix: substr assignements not optimized with -O2 When using -O2 or higher, assignements on substrings of unused variables were not being ignored, leading to wrong asm code generation. E.g. This single line: LET a$(1) = "." will generate wrong code. The assignement will be generated but the variable address will be removed, leading to inconsistent (wrong) code. --- api/optimize.py | 7 ++++ tests/functional/opt2_letsubstr_not_used.asm | 35 ++++++++++++++++++++ tests/functional/opt2_letsubstr_not_used.bas | 3 ++ 3 files changed, 45 insertions(+) create mode 100644 tests/functional/opt2_letsubstr_not_used.asm create mode 100644 tests/functional/opt2_letsubstr_not_used.bas diff --git a/api/optimize.py b/api/optimize.py index 69c818d2c..d48fd684e 100644 --- a/api/optimize.py +++ b/api/optimize.py @@ -150,6 +150,13 @@ def visit_LET(self, node): else: yield (yield self.generic_visit(node)) + def visit_LETSUBSTR(self, node): + if self.O_LEVEL > 1 and not node.children[0].accessed: + warning_not_used(node.children[0].lineno, node.children[0].name) + yield self.NOP + else: + yield (yield self.generic_visit(node)) + def visit_RETURN(self, node): """ Visits only children[1], since children[0] points to the current function being returned from (if any), and diff --git a/tests/functional/opt2_letsubstr_not_used.asm b/tests/functional/opt2_letsubstr_not_used.asm new file mode 100644 index 000000000..292c88772 --- /dev/null +++ b/tests/functional/opt2_letsubstr_not_used.asm @@ -0,0 +1,35 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + pop iy + pop ix + exx + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/opt2_letsubstr_not_used.bas b/tests/functional/opt2_letsubstr_not_used.bas new file mode 100644 index 000000000..2f22ae32a --- /dev/null +++ b/tests/functional/opt2_letsubstr_not_used.bas @@ -0,0 +1,3 @@ +DIM a$ +LET a$(1)="." + From 107f632526d0d4b9f545aa2c51a8caaf0f1eb6f5 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 1 Apr 2018 17:35:39 +0200 Subject: [PATCH 190/247] bugfix: add support for syntax a$(1)(4)="x" This add support for reading single char from an element of an array of strings: DIM a$(5) LET b$ = a$(3)(2) --- tests/functional/letarrstr_substr1.asm | 828 +++++++++++++++++++++++++ tests/functional/letarrstr_substr1.bas | 4 + zxbparser.py | 6 + 3 files changed, 838 insertions(+) create mode 100644 tests/functional/letarrstr_substr1.asm create mode 100644 tests/functional/letarrstr_substr1.bas diff --git a/tests/functional/letarrstr_substr1.asm b/tests/functional/letarrstr_substr1.asm new file mode 100644 index 000000000..4ef0ce8b3 --- /dev/null +++ b/tests/functional/letarrstr_substr1.asm @@ -0,0 +1,828 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld hl, (_a + 5) + call __LOADSTR + push hl + ld hl, 2 + push hl + ld hl, 2 + push hl + ld a, 1 + call __STRSLICE + ex de, hl + ld hl, _b + call __STORE_STR2 + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 69 "alloc.asm" +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 70 "alloc.asm" + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 30 "letarrstr_substr1.bas" +#line 1 "storestr2.asm" + + ; Similar to __STORE_STR, but this one is called when + ; the value of B$ if already duplicated onto the stack. + ; So we needn't call STRASSING to create a duplication + ; HL = address of string memory variable + ; DE = address of 2n string. It just copies DE into (HL) + ; freeing (HL) previously. + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 9 "storestr2.asm" + +__PISTORE_STR2: ; Indirect store temporary string at (IX + BC) + push ix + pop hl + add hl, bc + +__ISTORE_STR2: + ld c, (hl) ; Dereferences HL + inc hl + ld h, (hl) + ld l, c ; HL = *HL (real string variable address) + +__STORE_STR2: + push hl + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = *HL (real string address) + + push de + call __MEM_FREE + pop de + + pop hl + ld (hl), e + inc hl + ld (hl), d + dec hl ; HL points to mem address variable. This might be useful in the future. + + ret + +#line 31 "letarrstr_substr1.bas" +#line 1 "strslice.asm" + + ; String slicing library + ; HL = Str pointer + ; DE = String start + ; BC = String character end + ; A register => 0 => the HL pointer wont' be freed from the HEAP + ; e.g. a$(5 TO 10) => HL = a$; DE = 5; BC = 10 + + ; This implements a$(X to Y) being X and Y first and + ; last characters respectively. If X > Y, NULL is returned + + ; Otherwise returns a pointer to a$ FROM X to Y (starting from 0) + ; if Y > len(a$), then a$ will be padded with spaces (reallocating + ; it in dynamic memory if needed). Returns pointer (HL) to resulting + ; string. NULL (0) if no memory for padding. + ; + +#line 1 "strlen.asm" + + ; Returns len if a string + ; If a string is NULL, its len is also 0 + ; Result returned in HL + +__STRLEN: ; Direct FASTCALL entry + ld a, h + or l + ret z + + ld a, (hl) + inc hl + ld h, (hl) ; LEN(str) in HL + ld l, a + ret + + +#line 18 "strslice.asm" + + + +__STRSLICE: ; Callee entry + pop hl ; Return ADDRESS + pop bc ; Last char pos + pop de ; 1st char pos + ex (sp), hl ; CALLEE. -> String start + +__STRSLICE_FAST: ; __FASTCALL__ Entry + PROC + + LOCAL __CONT + LOCAL __EMPTY + LOCAL __FREE_ON_EXIT + + push hl ; Stores original HL pointer to be recovered on exit + ex af, af' ; Saves A register for later + + push hl + call __STRLEN + inc bc ; Last character position + 1 (string starts from 0) + or a + sbc hl, bc ; Compares length with last char position + jr nc, __CONT ; If Carry => We must copy to end of string + add hl, bc ; Restore back original LEN(a$) in HL + ld b, h + ld c, l ; Copy to the end of str + ccf ; Clears Carry flag for next subtraction + +__CONT: + ld h, b + ld l, c ; HL = Last char position to copy (1 for char 0, 2 for char 1, etc) + sbc hl, de ; HL = LEN(a$) - DE => Number of chars to copy + jr z, __EMPTY ; 0 Chars to copy => Return HL = 0 (NULL STR) + jr c, __EMPTY ; If Carry => Nothing to return (NULL STR) + + ld b, h + ld c, l ; BC = Number of chars to copy + inc bc + inc bc ; +2 bytes for string length number + + push bc + push de + call __MEM_ALLOC + pop de + pop bc + ld a, h + or l + jr z, __EMPTY ; Return if NULL (no memory) + + dec bc + dec bc ; Number of chars to copy (Len of slice) + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Stores new string length + + ex (sp), hl ; Pointer to A$ now in HL; Pointer to new string chars in Stack + inc hl + inc hl ; Skip string length + add hl, de ; Were to start from A$ + pop de ; Start of new string chars + push de ; Stores it again + ldir ; Copies BC chars + pop de + dec de + dec de ; Points to String LEN start + ex de, hl ; Returns it in HL + jr __FREE_ON_EXIT + +__EMPTY: ; Return NULL (empty) string + pop hl + ld hl, 0 ; Return NULL + + +__FREE_ON_EXIT: + ex af, af' ; Recover original A register + ex (sp), hl ; Original HL pointer + + or a + call nz, __MEM_FREE + + pop hl ; Recover result + ret + + ENDP + +#line 32 "letarrstr_substr1.bas" + +ZXBASIC_USER_DATA: +_b: + DEFB 00, 00 +_a: + DEFW 0000h + DEFB 02h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/letarrstr_substr1.bas b/tests/functional/letarrstr_substr1.bas new file mode 100644 index 000000000..ceb3170af --- /dev/null +++ b/tests/functional/letarrstr_substr1.bas @@ -0,0 +1,4 @@ +DIM a$(5) + +b$ = a$(1)(2) 'OK + diff --git a/zxbparser.py b/zxbparser.py index 7ea131e4c..b0bfa1f31 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -2339,6 +2339,12 @@ def p_string_func_call(p): p[0] = make_strslice(p.lineno(1), p[1], p[2][0], p[2][1]) +def p_string_func_call_single(p): + """ string : func_call LP expr RP + """ + p[0] = make_strslice(p.lineno(1), p[1], p[3], p[3]) + + def p_string_str(p): """ string : STRC """ From a6311b14ee2ebc5ccea5dd3f5cee2cd252b1eb51 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 1 Apr 2018 17:46:10 +0200 Subject: [PATCH 191/247] bugfix: allow STR x STR was requiring parenthesis. It should allow no parenthesis as all the other arity\1 functions. --- tests/functional/str1.asm | 897 ++++++++++++++++++++++++++++++++++++++ tests/functional/str1.bas | 2 + zxbparser.py | 8 +- 3 files changed, 903 insertions(+), 4 deletions(-) create mode 100644 tests/functional/str1.asm create mode 100644 tests/functional/str1.bas diff --git a/tests/functional/str1.asm b/tests/functional/str1.asm new file mode 100644 index 000000000..b9eb10408 --- /dev/null +++ b/tests/functional/str1.asm @@ -0,0 +1,897 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld de, __LABEL0 + ld hl, _a + call __STORE_STR + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__LABEL0: + DEFW 0001h + DEFB 31h +#line 1 "storestr.asm" + +; vim:ts=4:et:sw=4 + ; Stores value of current string pointed by DE register into address pointed by HL + ; Returns DE = Address pointer (&a$) + ; Returns HL = HL (b$ => might be needed later to free it from the heap) + ; + ; e.g. => HL = _variableName (DIM _variableName$) + ; DE = Address into the HEAP + ; + ; This function will resize (REALLOC) the space pointed by HL + ; before copying the content of b$ into a$ + + +#line 1 "strcpy.asm" + +#line 1 "realloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 70 "realloc.asm" +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 70 "alloc.asm" + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 71 "realloc.asm" +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 72 "realloc.asm" + + + ; --------------------------------------------------------------------- + ; MEM_REALLOC + ; Reallocates a block of memory in the heap. + ; + ; Parameters + ; HL = Pointer to the original block + ; BC = New Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; +; Notes: + ; If BC = 0, the block is freed, otherwise + ; the content of the original block is copied to the new one, and + ; the new size is adjusted. If BC < original length, the content + ; will be truncated. Otherwise, extra block content might contain + ; memory garbage. + ; + ; --------------------------------------------------------------------- +__REALLOC: ; Reallocates block pointed by HL, with new length BC + PROC + + LOCAL __REALLOC_END + + ld a, h + or l + jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc + + ld e, (hl) + inc hl + ld d, (hl) ; DE = First 2 bytes of HL block + + push hl + exx + pop de + inc de ; DE' <- HL + 2 + exx ; DE' <- HL (Saves current pointer into DE') + + dec hl ; HL = Block start + + push de + push bc + call __MEM_FREE ; Frees current block + pop bc + push bc + call __MEM_ALLOC ; Gets a new block of length BC + pop bc + pop de + + ld a, h + or l + ret z ; Return if HL == NULL (No memory) + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Recovers first 2 bytes in HL + + dec bc + dec bc ; BC = BC - 2 (Two bytes copied) + + ld a, b + or c + jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) + + exx + push de + exx + pop de ; DE <- DE' ; Start of remaining block + + push hl ; Saves current Block + 2 start + ex de, hl ; Exchanges them: DE is destiny block + ldir ; Copies BC Bytes + pop hl ; Recovers Block + 2 start + +__REALLOC_END: + + dec hl ; Set HL + dec hl ; To begin of block + ret + + ENDP + +#line 2 "strcpy.asm" + + ; String library + + +__STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) + PROC + + LOCAL __STRREALLOC + LOCAL __STRCONTINUE + LOCAL __B_IS_NULL + LOCAL __NOTHING_TO_COPY + + ld b, d + ld c, e + ld a, b + or c + jr z, __B_IS_NULL + + ex de, hl + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(b$) + ex de, hl ; DE = &b$ + +__B_IS_NULL: ; Jumps here if B$ pointer is NULL + inc bc + inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) + + push de + push hl + + ld a, h + or l + jr z, __STRREALLOC + + dec hl + ld d, (hl) + dec hl + ld e, (hl) ; DE = MEMBLOCKSIZE(a$) + dec de + dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) + + ld h, b + ld l, c ; HL = LEN(b$) + 2 => Minimum block size required + ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 + + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) + sbc hl, de ; Carry if len(b$) > Blocklen(a$) + jr c, __STRREALLOC ; No need to realloc + ; Need to reallocate at least to len(b$) + 2 + ex de, hl ; DE = Remaining bytes in a$ mem block. + ld hl, 4 + sbc hl, de ; if remaining bytes < 4 we can continue + jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes + +__STRREALLOC: + pop hl + call __REALLOC ; Returns in HL a new pointer with BC bytes allocated + push hl + +__STRCONTINUE: ; Pops hl and de SWAPPED + pop de ; DE = &a$ + pop hl ; HL = &b$ + + ld a, d ; Return if not enough memory for new length + or e + ret z ; Return if DE == NULL (0) + +__STRCPY: ; Copies string pointed by HL into string pointed by DE + ; Returns DE as HL (new pointer) + ld a, h + or l + jr z, __NOTHING_TO_COPY + ld c, (hl) + inc hl + ld b, (hl) + dec hl + inc bc + inc bc + push de + ldir + pop hl + ret + +__NOTHING_TO_COPY: + ex de, hl + ld (hl), e + inc hl + ld (hl), d + dec hl + ret + + ENDP + +#line 14 "storestr.asm" + +__PISTORE_STR: ; Indirect assignement at (IX + BC) + push ix + pop hl + add hl, bc + +__ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + +__STORE_STR: + push de ; Pointer to b$ + push hl ; Array pointer to variable memory address + + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation + ex de, hl ; DE = new address of a$ + pop hl ; Recover variable memory address pointer + + ld (hl), e + inc hl + ld (hl), d ; Stores a$ ptr into elemem ptr + + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) + ret + +#line 24 "str1.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 00, 00 +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/str1.bas b/tests/functional/str1.bas new file mode 100644 index 000000000..e3f108e02 --- /dev/null +++ b/tests/functional/str1.bas @@ -0,0 +1,2 @@ +LET a$=STR 1 + diff --git a/zxbparser.py b/zxbparser.py index b0bfa1f31..ab0bb5973 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -3029,13 +3029,13 @@ def p_sizeof(p): def p_str(p): - """ string : STR LP expr RP %prec UMINUS + """ string : STR expr %prec UMINUS """ - if is_number(p[3]): # A constant is converted to string directly - p[0] = symbols.STRING(str(p[3].value), p.lineno(1)) + if is_number(p[2]): # A constant is converted to string directly + p[0] = symbols.STRING(str(p[2].value), p.lineno(1)) else: p[0] = make_builtin(p.lineno(1), 'STR', - make_typecast(TYPE.float_, p[3], p.lineno(2)), + make_typecast(TYPE.float_, p[2], p.lineno(1)), type_=TYPE.string) From baf323136d96d26eacd3e31eac46564aaf204fb0 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 1 Apr 2018 17:51:53 +0200 Subject: [PATCH 192/247] make error message clearer Accessing strings as an lvalue is allowed only with one subscript index. --- zxbparser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zxbparser.py b/zxbparser.py index ab0bb5973..f6865c9cb 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -1087,7 +1087,7 @@ def p_substr_assignment(p): api.errmsg.syntax_error_expected_string(p.lineno(i - 1), r.type_) if len(q[1]) > 1: - syntax_error(p.lineno(i), "Too many values. Expected only one.") + syntax_error(p.lineno(i), "Accessing string with too many indexes. Expected only one.") return if len(q[1]) == 1: From 6a1b423a75451e192d347b345597e25f522bd333 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 1 Apr 2018 18:17:06 +0200 Subject: [PATCH 193/247] comment typos fixed --- zxbparser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zxbparser.py b/zxbparser.py index f6865c9cb..5188df801 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -1040,7 +1040,7 @@ def p_arr_assignment(p): i = 3 if q[1] is None or q[3] is None: - return # There where errors + return # There were errors p[0] = None # api.check.check_is_declared_strict(p.lineno(i - 1), q[0], classname='array') @@ -1067,7 +1067,7 @@ def p_substr_assignment(p): i = 3 if q[1] is None or q[3] is None: - return # There where errors + return # There were errors p[0] = None # api.check.check_is_declared_strict(p.lineno(i - 1), q[0], classname='array') From 9de8501637f76565c1485c7be32fdf7d76737c13 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 1 Apr 2018 19:05:28 +0200 Subject: [PATCH 194/247] allow substr assignment with no LET This allows a$(x)="." --- tests/functional/lvalsubstr_nolet.asm | 808 ++++++++++++++++++++++++++ tests/functional/lvalsubstr_nolet.bas | 3 + zxbparser.py | 71 ++- 3 files changed, 853 insertions(+), 29 deletions(-) create mode 100644 tests/functional/lvalsubstr_nolet.asm create mode 100644 tests/functional/lvalsubstr_nolet.bas diff --git a/tests/functional/lvalsubstr_nolet.asm b/tests/functional/lvalsubstr_nolet.asm new file mode 100644 index 000000000..c0fe1dacd --- /dev/null +++ b/tests/functional/lvalsubstr_nolet.asm @@ -0,0 +1,808 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld hl, __LABEL0 + call __LOADSTR + push hl + xor a + push af + ld hl, 1 + push hl + ld hl, 1 + push hl + ld hl, (_a) + call __LETSUBSTR + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__LABEL0: + DEFW 0001h + DEFB 2Eh +#line 1 "letsubstr.asm" + + ; Substring assigment eg. LET a$(p0 TO p1) = "xxxx" + ; HL = Start of string + ; TOP of the stack -> p1 (16 bit, unsigned) + ; TOP -1 of the stack -> p0 register + ; TOP -2 Flag (popped out in A register) + ; A Register => 0 if HL is not freed from memory + ; => Not 0 if HL must be freed from memory on exit + ; TOP -3 B$ address + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 11 "letsubstr.asm" + +__LETSUBSTR: + PROC + + LOCAL __CONT0 + LOCAL __CONT1 + LOCAL __CONT2 + LOCAL __FREE_STR + LOCAL __FREE_STR0 + + exx + pop hl ; Return address + pop de ; p1 + pop bc ; p0 + exx + + pop af ; Flag + ex af, af' ; Save it for later + + pop de ; B$ + + exx + push hl ; push ret addr back + exx + + ld a, h + or l + jp z, __FREE_STR0 ; Return if null + + ld c, (hl) + inc hl + ld b, (hl) ; BC = Str length + inc hl ; HL = String start + push bc + + exx + ex de, hl + or a + sbc hl, bc ; HL = Length of string requester by user + inc hl ; len (a$(p0 TO p1)) = p1 - p0 + 1 + ex de, hl ; Saves it in DE + + pop hl ; HL = String length + exx + jp c, __FREE_STR0 ; Return if greather + exx ; Return if p0 > p1 + + or a + sbc hl, bc ; P0 >= String length? + exx + + jp z, __FREE_STR0 ; Return if equal + jp c, __FREE_STR0 ; Return if greather + + exx + add hl, bc ; Add it back + + sbc hl, de ; Length of substring > string => Truncate it + add hl, de ; add it back + jr nc, __CONT0 ; Length of substring within a$ + + ld d, h + ld e, l ; Truncate length of substring to fit within the strlen + +__CONT0: ; At this point DE = Length of subtring to copy + ; BC = start of char to copy + push de + + push bc + exx + pop bc + + add hl, bc ; Start address (within a$) so copy from b$ (in DE) + + push hl + exx + pop hl ; Start address (within a$) so copy from b$ (in DE) + + ld b, d ; Length of string + ld c, e + + ld (hl), ' ' + ld d, h + ld e, l + inc de + dec bc + ld a, b + or c + jr z, __CONT2 + + ; At this point HL = DE = Start of Write zone in a$ + ; BC = Number of chars to write + + ldir + +__CONT2: + + pop bc ; Recovers Length of string to copy + exx + ex de, hl ; HL = Source, DE = Target + + ld a, h + or l + jp z, __FREE_STR ; Return if B$ is NULL + + ld c, (hl) + inc hl + ld b, (hl) + inc hl + + ld a, b + or c + jp z, __FREE_STR ; Return if len(b$) = 0 + + ; Now if len(b$) < len(char to copy), copy only len(b$) chars + + push de + push hl + push bc + exx + pop hl ; LEN (b$) + or a + sbc hl, bc + add hl, bc + jr nc, __CONT1 + + ; If len(b$) < len(to copy) + ld b, h ; BC = len(to copy) + ld c, l + +__CONT1: + pop hl + pop de + ldir ; Copy b$ into a$(x to y) + + exx + ex de, hl + +__FREE_STR0: + ex de, hl + +__FREE_STR: + ex af, af' + or a ; If not 0, free + jp nz, __MEM_FREE + ret + + ENDP + +#line 32 "lvalsubstr_nolet.bas" +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 69 "alloc.asm" + + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 33 "lvalsubstr_nolet.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 00, 00 +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/lvalsubstr_nolet.bas b/tests/functional/lvalsubstr_nolet.bas new file mode 100644 index 000000000..e57d2cdb5 --- /dev/null +++ b/tests/functional/lvalsubstr_nolet.bas @@ -0,0 +1,3 @@ +DIM a$ +a$(1)="." + diff --git a/zxbparser.py b/zxbparser.py index 5188df801..7b52f2468 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -1056,60 +1056,73 @@ def p_arr_assignment(p): p[0] = make_sentence('LETARRAY', arr, expr) -def p_substr_assignment(p): - """ statement : ID arg_list EQ expr - | LET ID arg_list EQ expr +def p_substr_assignment_no_let(p): + """ statement : ID LP expr RP EQ expr """ - q = p[1:] - i = 2 - if q[0].upper() == 'LET': - q = q[1:] - i = 3 + # This can be only a substr assignment like a$(i + 3) = ".", since arrays + # have ARRAY_ID already + entry = SYMBOL_TABLE.access_call(p[1], p.lineno(1)) + if entry is None: + return - if q[1] is None or q[3] is None: + if entry.class_ == CLASS.unknown: + entry.class_ = CLASS.var + + if p[6].type_ != TYPE.string: + api.errmsg.syntax_error_expected_string(p.lineno(5), p[6].type_) + + lineno = p.lineno(2) + base = make_number(OPTIONS.string_base.value, lineno, _TYPE(gl.STR_INDEX_TYPE)) + substr = make_typecast(_TYPE(gl.STR_INDEX_TYPE), p[3], lineno) + p[0] = make_sentence('LETSUBSTR', entry, + make_binary(lineno, 'MINUS', substr, base, func=lambda x, y: x - y), + make_binary(lineno, 'MINUS', substr, base, func=lambda x, y: x - y), + p[6]) + + +def p_substr_assignment(p): + """ statement : LET ID arg_list EQ expr + """ + if p[3] is None or p[5] is None: return # There were errors p[0] = None - # api.check.check_is_declared_strict(p.lineno(i - 1), q[0], classname='array') - - entry = SYMBOL_TABLE.access_call(q[0], p.lineno(i - 1)) + entry = SYMBOL_TABLE.access_call(p[2], p.lineno(2)) if entry is None: - # variable = SYMBOL_TABLE.make_var(q[0], p.lineno(1), TYPE.string) - # entry = SYMBOL_TABLE.get_id_entry(q[0]) return if entry.class_ == CLASS.unknown: entry.class_ = CLASS.var assert entry.class_ == CLASS.var and entry.type_ == TYPE.string - r = q[3] - if r.type_ != TYPE.string: - api.errmsg.syntax_error_expected_string(p.lineno(i - 1), r.type_) - if len(q[1]) > 1: - syntax_error(p.lineno(i), "Accessing string with too many indexes. Expected only one.") + if p[5].type_ != TYPE.string: + api.errmsg.syntax_error_expected_string(p.lineno(4), p[5].type_) + + if len(p[3]) > 1: + syntax_error(p.lineno(2), "Accessing string with too many indexes. Expected only one.") return - if len(q[1]) == 1: + if len(p[3]) == 1: substr = ( - make_typecast(_TYPE(gl.STR_INDEX_TYPE), q[1][0].value, p.lineno(i)), - make_typecast(_TYPE(gl.STR_INDEX_TYPE), q[1][0].value, p.lineno(i))) + make_typecast(_TYPE(gl.STR_INDEX_TYPE), p[3][0].value, p.lineno(2)), + make_typecast(_TYPE(gl.STR_INDEX_TYPE), p[3][0].value, p.lineno(2))) else: substr = (make_typecast(_TYPE(gl.STR_INDEX_TYPE), make_number(gl.MIN_STRSLICE_IDX, - lineno=p.lineno(i)), - p.lineno(i)), + lineno=p.lineno(2)), + p.lineno(2)), make_typecast(_TYPE(gl.STR_INDEX_TYPE), make_number(gl.MAX_STRSLICE_IDX, - lineno=p.lineno(i)), - p.lineno(i))) + lineno=p.lineno(2)), + p.lineno(2))) - lineno = p.lineno(0) + lineno = p.lineno(2) base = make_number(OPTIONS.string_base.value, lineno, _TYPE(gl.STR_INDEX_TYPE)) p[0] = make_sentence('LETSUBSTR', entry, make_binary(lineno, 'MINUS', substr[0], base, func=lambda x, y: x - y), make_binary(lineno, 'MINUS', substr[1], base, func=lambda x, y: x - y), - r) + p[5]) def p_str_assign(p): @@ -2298,7 +2311,7 @@ def p_BNOT_expr(p): def p_lp_expr_rp(p): - """ bexpr : LP expr RP + """ bexpr : LP expr RP %prec ID """ p[0] = p[2] From b506c8b98dafc1f68479ab01c42f4c5f9ea9d431 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 2 Apr 2018 18:30:02 +0200 Subject: [PATCH 195/247] bugfix: substring of str expression Expressions like (a$ + "x")(5 TO) crashed the compiler due to a bug. Fixed. --- tests/functional/substr_expr.asm | 902 +++++++++++++++++++++++++++ tests/functional/substr_expr.bas | 3 + tests/functional/substr_expr_err.bas | 3 + tests/functional/test_errmsg.txt | 2 + zxbparser.py | 8 +- 5 files changed, 914 insertions(+), 4 deletions(-) create mode 100644 tests/functional/substr_expr.asm create mode 100644 tests/functional/substr_expr.bas create mode 100644 tests/functional/substr_expr_err.bas diff --git a/tests/functional/substr_expr.asm b/tests/functional/substr_expr.asm new file mode 100644 index 000000000..3250032d9 --- /dev/null +++ b/tests/functional/substr_expr.asm @@ -0,0 +1,902 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld de, __LABEL0 + ld hl, (_a) + call __ADDSTR + push hl + ld hl, 5 + push hl + ld hl, 65534 + push hl + ld a, 1 + call __STRSLICE + ex de, hl + ld hl, _b + call __STORE_STR2 + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__LABEL0: + DEFW 0001h + DEFB 2Eh +#line 1 "storestr2.asm" + + ; Similar to __STORE_STR, but this one is called when + ; the value of B$ if already duplicated onto the stack. + ; So we needn't call STRASSING to create a duplication + ; HL = address of string memory variable + ; DE = address of 2n string. It just copies DE into (HL) + ; freeing (HL) previously. + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 9 "storestr2.asm" + +__PISTORE_STR2: ; Indirect store temporary string at (IX + BC) + push ix + pop hl + add hl, bc + +__ISTORE_STR2: + ld c, (hl) ; Dereferences HL + inc hl + ld h, (hl) + ld l, c ; HL = *HL (real string variable address) + +__STORE_STR2: + push hl + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = *HL (real string address) + + push de + call __MEM_FREE + pop de + + pop hl + ld (hl), e + inc hl + ld (hl), d + dec hl ; HL points to mem address variable. This might be useful in the future. + + ret + +#line 34 "substr_expr.bas" +#line 1 "strcat.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 69 "alloc.asm" + + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "strcat.asm" +#line 1 "strlen.asm" + + ; Returns len if a string + ; If a string is NULL, its len is also 0 + ; Result returned in HL + +__STRLEN: ; Direct FASTCALL entry + ld a, h + or l + ret z + + ld a, (hl) + inc hl + ld h, (hl) ; LEN(str) in HL + ld l, a + ret + + +#line 3 "strcat.asm" + +__ADDSTR: ; Implements c$ = a$ + b$ + ; hl = &a$, de = &b$ (pointers) + + +__STRCAT2: ; This routine creates a new string in dynamic space + ; making room for it. Then copies a$ + b$ into it. + ; HL = a$, DE = b$ + + PROC + + LOCAL __STR_CONT + LOCAL __STRCATEND + + push hl + call __STRLEN + ld c, l + ld b, h ; BC = LEN(a$) + ex (sp), hl ; (SP) = LEN (a$), HL = a$ + push hl ; Saves pointer to a$ + + inc bc + inc bc ; +2 bytes to store length + + ex de, hl + push hl + call __STRLEN + ; HL = len(b$) + + add hl, bc ; Total str length => 2 + len(a$) + len(b$) + + ld c, l + ld b, h ; BC = Total str length + 2 + call __MEM_ALLOC + pop de ; HL = c$, DE = b$ + + ex de, hl ; HL = b$, DE = c$ + ex (sp), hl ; HL = a$, (SP) = b$ + + exx + pop de ; D'E' = b$ + exx + + pop bc ; LEN(a$) + + ld a, d + or e + ret z ; If no memory: RETURN + +__STR_CONT: + push de ; Address of c$ + + ld a, h + or l + jr nz, __STR_CONT1 ; If len(a$) != 0 do copy + + ; a$ is NULL => uses HL = DE for transfer + ld h, d + ld l, e + ld (hl), a ; This will copy 00 00 at (DE) location + inc de ; + dec bc ; Ensure BC will be set to 1 in the next step + +__STR_CONT1: ; Copies a$ (HL) into c$ (DE) + inc bc + inc bc ; BC = BC + 2 + ldir ; MEMCOPY: c$ = a$ + pop hl ; HL = c$ + + exx + push de ; Recovers b$; A ex hl,hl' would be very handy + exx + + pop de ; DE = b$ + +__STRCAT: ; ConCATenate two strings a$ = a$ + b$. HL = ptr to a$, DE = ptr to b$ + ; NOTE: Both DE, BC and AF are modified and lost + ; Returns HL (pointer to a$) + ; a$ Must be NOT NULL + ld a, d + or e + ret z ; Returns if de is NULL (nothing to copy) + + push hl ; Saves HL to return it later + + ld c, (hl) + inc hl + ld b, (hl) + inc hl + add hl, bc ; HL = end of (a$) string ; bc = len(a$) + push bc ; Saves LEN(a$) for later + + ex de, hl ; DE = end of string (Begin of copy addr) + ld c, (hl) + inc hl + ld b, (hl) ; BC = len(b$) + + ld a, b + or c + jr z, __STRCATEND; Return if len(b$) == 0 + + push bc ; Save LEN(b$) + inc hl ; Skip 2nd byte of len(b$) + ldir ; Concatenate b$ + + pop bc ; Recovers length (b$) + pop hl ; Recovers length (a$) + add hl, bc ; HL = LEN(a$) + LEN(b$) = LEN(a$+b$) + ex de, hl ; DE = LEN(a$+b$) + pop hl + + ld (hl), e ; Updates new LEN and return + inc hl + ld (hl), d + dec hl + ret + +__STRCATEND: + pop hl ; Removes Len(a$) + pop hl ; Restores original HL, so HL = a$ + ret + + ENDP + +#line 35 "substr_expr.bas" +#line 1 "strslice.asm" + + ; String slicing library + ; HL = Str pointer + ; DE = String start + ; BC = String character end + ; A register => 0 => the HL pointer wont' be freed from the HEAP + ; e.g. a$(5 TO 10) => HL = a$; DE = 5; BC = 10 + + ; This implements a$(X to Y) being X and Y first and + ; last characters respectively. If X > Y, NULL is returned + + ; Otherwise returns a pointer to a$ FROM X to Y (starting from 0) + ; if Y > len(a$), then a$ will be padded with spaces (reallocating + ; it in dynamic memory if needed). Returns pointer (HL) to resulting + ; string. NULL (0) if no memory for padding. + ; + + + + + +__STRSLICE: ; Callee entry + pop hl ; Return ADDRESS + pop bc ; Last char pos + pop de ; 1st char pos + ex (sp), hl ; CALLEE. -> String start + +__STRSLICE_FAST: ; __FASTCALL__ Entry + PROC + + LOCAL __CONT + LOCAL __EMPTY + LOCAL __FREE_ON_EXIT + + push hl ; Stores original HL pointer to be recovered on exit + ex af, af' ; Saves A register for later + + push hl + call __STRLEN + inc bc ; Last character position + 1 (string starts from 0) + or a + sbc hl, bc ; Compares length with last char position + jr nc, __CONT ; If Carry => We must copy to end of string + add hl, bc ; Restore back original LEN(a$) in HL + ld b, h + ld c, l ; Copy to the end of str + ccf ; Clears Carry flag for next subtraction + +__CONT: + ld h, b + ld l, c ; HL = Last char position to copy (1 for char 0, 2 for char 1, etc) + sbc hl, de ; HL = LEN(a$) - DE => Number of chars to copy + jr z, __EMPTY ; 0 Chars to copy => Return HL = 0 (NULL STR) + jr c, __EMPTY ; If Carry => Nothing to return (NULL STR) + + ld b, h + ld c, l ; BC = Number of chars to copy + inc bc + inc bc ; +2 bytes for string length number + + push bc + push de + call __MEM_ALLOC + pop de + pop bc + ld a, h + or l + jr z, __EMPTY ; Return if NULL (no memory) + + dec bc + dec bc ; Number of chars to copy (Len of slice) + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Stores new string length + + ex (sp), hl ; Pointer to A$ now in HL; Pointer to new string chars in Stack + inc hl + inc hl ; Skip string length + add hl, de ; Were to start from A$ + pop de ; Start of new string chars + push de ; Stores it again + ldir ; Copies BC chars + pop de + dec de + dec de ; Points to String LEN start + ex de, hl ; Returns it in HL + jr __FREE_ON_EXIT + +__EMPTY: ; Return NULL (empty) string + pop hl + ld hl, 0 ; Return NULL + + +__FREE_ON_EXIT: + ex af, af' ; Recover original A register + ex (sp), hl ; Original HL pointer + + or a + call nz, __MEM_FREE + + pop hl ; Recover result + ret + + ENDP + +#line 36 "substr_expr.bas" + +ZXBASIC_USER_DATA: +_b: + DEFB 00, 00 +_a: + DEFB 00, 00 +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/substr_expr.bas b/tests/functional/substr_expr.bas new file mode 100644 index 000000000..c40764a66 --- /dev/null +++ b/tests/functional/substr_expr.bas @@ -0,0 +1,3 @@ + +LET b$ = (a$ + ".")(5 TO ) + diff --git a/tests/functional/substr_expr_err.bas b/tests/functional/substr_expr_err.bas new file mode 100644 index 000000000..841804678 --- /dev/null +++ b/tests/functional/substr_expr_err.bas @@ -0,0 +1,3 @@ +DIM a as Byte +LET c$ = (a)(5 TO ) + diff --git a/tests/functional/test_errmsg.txt b/tests/functional/test_errmsg.txt index 76aa808c8..ff105f384 100644 --- a/tests/functional/test_errmsg.txt +++ b/tests/functional/test_errmsg.txt @@ -115,4 +115,6 @@ asmerror2.asm:2: Error: illegal preprocessor character '@' asmerror2.asm:2: Syntax error. Unexpected end of line [NEWLINE] >>> process_file('llb.bas') llb.bas:3: Undeclared function "f$" +>>> process_file('substr_expr_err.bas') +substr_expr_err.bas:3: Expected a string type expression. Got byte type instead diff --git a/zxbparser.py b/zxbparser.py index 7b52f2468..b393b018a 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -2397,13 +2397,13 @@ def p_string_substr(p): def p_string_expr_lp(p): """ string : LP expr RP substr """ - if p[1].type_ != TYPE.string: + if p[2].type_ != TYPE.string: syntax_error(p.lexer.lineno, - "Expected a TYPE.string type expression. " - "Got '%s' one instead" % TYPE.to_string(p[1].type_)) + "Expected a string type expression. " + "Got %s type instead" % TYPE.to_string(p[2].type_)) p[0] = None else: - p[0] = make_strslice(p.lexer.lineno, p[1], p[2][0], p[2][1]) + p[0] = make_strslice(p.lexer.lineno, p[2], p[4][0], p[4][1]) def p_subind_str(p): From cf7aa0f478ca566daf1456882e7952eb7dd454ba Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Thu, 5 Apr 2018 23:25:06 +0200 Subject: [PATCH 196/247] bugfix: allow no blank line between DECLAREs using DECLARE required a blank line after it. So the following sequence: DECLARE FUNCTION f() DECLARE FUNCTION q() raised a syntax error despite the fact it is ok. --- tests/functional/fwd_func_decl.asm | 51 ++++++++++++++++++++++++++++++ tests/functional/fwd_func_decl.bas | 12 +++++++ zxbparser.py | 18 +++++------ 3 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 tests/functional/fwd_func_decl.asm create mode 100644 tests/functional/fwd_func_decl.bas diff --git a/tests/functional/fwd_func_decl.asm b/tests/functional/fwd_func_decl.asm new file mode 100644 index 000000000..7c53d3721 --- /dev/null +++ b/tests/functional/fwd_func_decl.asm @@ -0,0 +1,51 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +_f: + push ix + ld ix, 0 + add ix, sp +_f__leave: + ld sp, ix + pop ix + ret +_q: + push ix + ld ix, 0 + add ix, sp +_q__leave: + ld sp, ix + pop ix + ret + +ZXBASIC_USER_DATA: + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/fwd_func_decl.bas b/tests/functional/fwd_func_decl.bas new file mode 100644 index 000000000..dfe29bd90 --- /dev/null +++ b/tests/functional/fwd_func_decl.bas @@ -0,0 +1,12 @@ + + +declare function f() +declare function q() + +function f() +end function + +function q() +end function + + diff --git a/zxbparser.py b/zxbparser.py index b393b018a..a16dc3178 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -2645,8 +2645,7 @@ def p_funcdeclforward(p): def p_function_header(p): - """ function_header : function_def param_decl typedef NEWLINE - | function_def param_decl typedef CO + """ function_header : function_def param_decl typedef """ if p[1] is None or p[2] is None: p[0] = None @@ -2657,13 +2656,14 @@ def p_function_header(p): p[0] = p[1] p[0].appendChild(p[2]) p[0].params_size = p[2].size + lineno = p.lineno(3) previoustype_ = p[0].type_ if not p[3].implicit or p[0].entry.type_ is None or p[0].entry.type_ == TYPE.unknown: p[0].type_ = p[3] if forwarded and previoustype_ != p[0].type_: - api.errmsg.syntax_error_func_type_mismatch(p.lineno(4), p[0].entry) + api.errmsg.syntax_error_func_type_mismatch(lineno, p[0].entry) p[0] = None return @@ -2672,24 +2672,24 @@ def p_function_header(p): p2 = p[2].children if len(p1) != len(p2): - api.errmsg.syntax_error_parameter_mismatch(p.lineno(4), p[0].entry) + api.errmsg.syntax_error_parameter_mismatch(lineno, p[0].entry) p[0] = None return for a, b in zip(p1, p2): if a.name != b.name: - warning(p.lineno(4), "Parameter '%s' in function '%s' has been renamed to '%s'" % + warning(lineno, "Parameter '%s' in function '%s' has been renamed to '%s'" % (a.name, p[0].name, b.name)) if a.type_ != b.type_ or a.byref != b.byref: - api.errmsg.syntax_error_parameter_mismatch(p.lineno(4), p[0].entry) + api.errmsg.syntax_error_parameter_mismatch(lineno, p[0].entry) p[0] = None return p[0].entry.params = p[2] if FUNCTION_LEVEL[-1].kind == KIND.sub and not p[3].implicit: - syntax_error(p.lineno(4), 'SUBs cannot have a return type definition') + syntax_error(lineno, 'SUBs cannot have a return type definition') p[0] = None return @@ -2698,8 +2698,8 @@ def p_function_header(p): if p[0].entry.convention == CONVENTION.fastcall and len(p[2]) > 1: kind = 'SUB' if FUNCTION_LEVEL[-1].kind == KIND.sub else 'FUNCTION' - warning(p.lineno(4), "%s '%s' declared as FASTCALL with %i parameters" % (kind, p[0].entry.name, - len(p[2]))) + warning(lineno, "%s '%s' declared as FASTCALL with %i parameters" % (kind, p[0].entry.name, + len(p[2]))) def p_function_error(p): From e8cc9cd635ac86dad3bd42be1663767e552f1c8b Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 1 Apr 2018 17:31:42 +0200 Subject: [PATCH 197/247] add test cases to increase coverage This covers syntax rules: string : func_call substr substr : LP TO RP string : string substr string : string LP expr RP bexpr : __LINE__ bexpr : __FILE__ statement : ID substr EQ expr --- tests/functional/dup_func_decl.bas | 7 + tests/functional/file_macro.asm | 910 +++++++++++++++++++++++++ tests/functional/file_macro.bas | 5 + tests/functional/id_substr_eq_expr.asm | 812 ++++++++++++++++++++++ tests/functional/id_substr_eq_expr.bas | 3 + tests/functional/letarrstr_substr0.asm | 828 ++++++++++++++++++++++ tests/functional/letarrstr_substr0.bas | 4 + tests/functional/line_macro.asm | 39 ++ tests/functional/line_macro.bas | 6 + tests/functional/string_substr.asm | 779 +++++++++++++++++++++ tests/functional/string_substr.bas | 3 + tests/functional/substr_empty.asm | 896 ++++++++++++++++++++++++ tests/functional/substr_empty.bas | 3 + tests/functional/substr_empty2.asm | 902 ++++++++++++++++++++++++ tests/functional/substr_empty2.bas | 2 + tests/functional/substr_expr2.asm | 780 +++++++++++++++++++++ tests/functional/substr_expr2.bas | 4 + tests/functional/test_errmsg.txt | 2 + 18 files changed, 5985 insertions(+) create mode 100644 tests/functional/dup_func_decl.bas create mode 100644 tests/functional/file_macro.asm create mode 100644 tests/functional/file_macro.bas create mode 100644 tests/functional/id_substr_eq_expr.asm create mode 100644 tests/functional/id_substr_eq_expr.bas create mode 100644 tests/functional/letarrstr_substr0.asm create mode 100644 tests/functional/letarrstr_substr0.bas create mode 100644 tests/functional/line_macro.asm create mode 100644 tests/functional/line_macro.bas create mode 100644 tests/functional/string_substr.asm create mode 100644 tests/functional/string_substr.bas create mode 100644 tests/functional/substr_empty.asm create mode 100644 tests/functional/substr_empty.bas create mode 100644 tests/functional/substr_empty2.asm create mode 100644 tests/functional/substr_empty2.bas create mode 100644 tests/functional/substr_expr2.asm create mode 100644 tests/functional/substr_expr2.bas diff --git a/tests/functional/dup_func_decl.bas b/tests/functional/dup_func_decl.bas new file mode 100644 index 000000000..ead72b4f0 --- /dev/null +++ b/tests/functional/dup_func_decl.bas @@ -0,0 +1,7 @@ + + +declare function f() + +declare function f() + + diff --git a/tests/functional/file_macro.asm b/tests/functional/file_macro.asm new file mode 100644 index 000000000..943dd8e4a --- /dev/null +++ b/tests/functional/file_macro.asm @@ -0,0 +1,910 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld de, __LABEL0 + ld hl, _a + call __STORE_STR + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__LABEL0: + DEFW 000Eh + DEFB 66h + DEFB 69h + DEFB 6Ch + DEFB 65h + DEFB 5Fh + DEFB 6Dh + DEFB 61h + DEFB 63h + DEFB 72h + DEFB 6Fh + DEFB 2Eh + DEFB 62h + DEFB 61h + DEFB 73h +#line 1 "storestr.asm" + +; vim:ts=4:et:sw=4 + ; Stores value of current string pointed by DE register into address pointed by HL + ; Returns DE = Address pointer (&a$) + ; Returns HL = HL (b$ => might be needed later to free it from the heap) + ; + ; e.g. => HL = _variableName (DIM _variableName$) + ; DE = Address into the HEAP + ; + ; This function will resize (REALLOC) the space pointed by HL + ; before copying the content of b$ into a$ + + +#line 1 "strcpy.asm" + +#line 1 "realloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 70 "realloc.asm" +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 70 "alloc.asm" + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 71 "realloc.asm" +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 72 "realloc.asm" + + + ; --------------------------------------------------------------------- + ; MEM_REALLOC + ; Reallocates a block of memory in the heap. + ; + ; Parameters + ; HL = Pointer to the original block + ; BC = New Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; +; Notes: + ; If BC = 0, the block is freed, otherwise + ; the content of the original block is copied to the new one, and + ; the new size is adjusted. If BC < original length, the content + ; will be truncated. Otherwise, extra block content might contain + ; memory garbage. + ; + ; --------------------------------------------------------------------- +__REALLOC: ; Reallocates block pointed by HL, with new length BC + PROC + + LOCAL __REALLOC_END + + ld a, h + or l + jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc + + ld e, (hl) + inc hl + ld d, (hl) ; DE = First 2 bytes of HL block + + push hl + exx + pop de + inc de ; DE' <- HL + 2 + exx ; DE' <- HL (Saves current pointer into DE') + + dec hl ; HL = Block start + + push de + push bc + call __MEM_FREE ; Frees current block + pop bc + push bc + call __MEM_ALLOC ; Gets a new block of length BC + pop bc + pop de + + ld a, h + or l + ret z ; Return if HL == NULL (No memory) + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Recovers first 2 bytes in HL + + dec bc + dec bc ; BC = BC - 2 (Two bytes copied) + + ld a, b + or c + jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) + + exx + push de + exx + pop de ; DE <- DE' ; Start of remaining block + + push hl ; Saves current Block + 2 start + ex de, hl ; Exchanges them: DE is destiny block + ldir ; Copies BC Bytes + pop hl ; Recovers Block + 2 start + +__REALLOC_END: + + dec hl ; Set HL + dec hl ; To begin of block + ret + + ENDP + +#line 2 "strcpy.asm" + + ; String library + + +__STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) + PROC + + LOCAL __STRREALLOC + LOCAL __STRCONTINUE + LOCAL __B_IS_NULL + LOCAL __NOTHING_TO_COPY + + ld b, d + ld c, e + ld a, b + or c + jr z, __B_IS_NULL + + ex de, hl + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(b$) + ex de, hl ; DE = &b$ + +__B_IS_NULL: ; Jumps here if B$ pointer is NULL + inc bc + inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) + + push de + push hl + + ld a, h + or l + jr z, __STRREALLOC + + dec hl + ld d, (hl) + dec hl + ld e, (hl) ; DE = MEMBLOCKSIZE(a$) + dec de + dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) + + ld h, b + ld l, c ; HL = LEN(b$) + 2 => Minimum block size required + ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 + + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) + sbc hl, de ; Carry if len(b$) > Blocklen(a$) + jr c, __STRREALLOC ; No need to realloc + ; Need to reallocate at least to len(b$) + 2 + ex de, hl ; DE = Remaining bytes in a$ mem block. + ld hl, 4 + sbc hl, de ; if remaining bytes < 4 we can continue + jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes + +__STRREALLOC: + pop hl + call __REALLOC ; Returns in HL a new pointer with BC bytes allocated + push hl + +__STRCONTINUE: ; Pops hl and de SWAPPED + pop de ; DE = &a$ + pop hl ; HL = &b$ + + ld a, d ; Return if not enough memory for new length + or e + ret z ; Return if DE == NULL (0) + +__STRCPY: ; Copies string pointed by HL into string pointed by DE + ; Returns DE as HL (new pointer) + ld a, h + or l + jr z, __NOTHING_TO_COPY + ld c, (hl) + inc hl + ld b, (hl) + dec hl + inc bc + inc bc + push de + ldir + pop hl + ret + +__NOTHING_TO_COPY: + ex de, hl + ld (hl), e + inc hl + ld (hl), d + dec hl + ret + + ENDP + +#line 14 "storestr.asm" + +__PISTORE_STR: ; Indirect assignement at (IX + BC) + push ix + pop hl + add hl, bc + +__ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + +__STORE_STR: + push de ; Pointer to b$ + push hl ; Array pointer to variable memory address + + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation + ex de, hl ; DE = new address of a$ + pop hl ; Recover variable memory address pointer + + ld (hl), e + inc hl + ld (hl), d ; Stores a$ ptr into elemem ptr + + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) + ret + +#line 37 "file_macro.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 00, 00 +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/file_macro.bas b/tests/functional/file_macro.bas new file mode 100644 index 000000000..ce6ece335 --- /dev/null +++ b/tests/functional/file_macro.bas @@ -0,0 +1,5 @@ + +#line 3 "file_macro.bas" +LET a$ = __FILE__ + + diff --git a/tests/functional/id_substr_eq_expr.asm b/tests/functional/id_substr_eq_expr.asm new file mode 100644 index 000000000..0467871a9 --- /dev/null +++ b/tests/functional/id_substr_eq_expr.asm @@ -0,0 +1,812 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld hl, __LABEL0 + call __LOADSTR + push hl + xor a + push af + ld hl, 1 + push hl + ld hl, 5 + push hl + ld hl, (_a) + call __LETSUBSTR + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__LABEL0: + DEFW 0005h + DEFB 48h + DEFB 65h + DEFB 6Ch + DEFB 6Ch + DEFB 6Fh +#line 1 "letsubstr.asm" + + ; Substring assigment eg. LET a$(p0 TO p1) = "xxxx" + ; HL = Start of string + ; TOP of the stack -> p1 (16 bit, unsigned) + ; TOP -1 of the stack -> p0 register + ; TOP -2 Flag (popped out in A register) + ; A Register => 0 if HL is not freed from memory + ; => Not 0 if HL must be freed from memory on exit + ; TOP -3 B$ address + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 11 "letsubstr.asm" + +__LETSUBSTR: + PROC + + LOCAL __CONT0 + LOCAL __CONT1 + LOCAL __CONT2 + LOCAL __FREE_STR + LOCAL __FREE_STR0 + + exx + pop hl ; Return address + pop de ; p1 + pop bc ; p0 + exx + + pop af ; Flag + ex af, af' ; Save it for later + + pop de ; B$ + + exx + push hl ; push ret addr back + exx + + ld a, h + or l + jp z, __FREE_STR0 ; Return if null + + ld c, (hl) + inc hl + ld b, (hl) ; BC = Str length + inc hl ; HL = String start + push bc + + exx + ex de, hl + or a + sbc hl, bc ; HL = Length of string requester by user + inc hl ; len (a$(p0 TO p1)) = p1 - p0 + 1 + ex de, hl ; Saves it in DE + + pop hl ; HL = String length + exx + jp c, __FREE_STR0 ; Return if greather + exx ; Return if p0 > p1 + + or a + sbc hl, bc ; P0 >= String length? + exx + + jp z, __FREE_STR0 ; Return if equal + jp c, __FREE_STR0 ; Return if greather + + exx + add hl, bc ; Add it back + + sbc hl, de ; Length of substring > string => Truncate it + add hl, de ; add it back + jr nc, __CONT0 ; Length of substring within a$ + + ld d, h + ld e, l ; Truncate length of substring to fit within the strlen + +__CONT0: ; At this point DE = Length of subtring to copy + ; BC = start of char to copy + push de + + push bc + exx + pop bc + + add hl, bc ; Start address (within a$) so copy from b$ (in DE) + + push hl + exx + pop hl ; Start address (within a$) so copy from b$ (in DE) + + ld b, d ; Length of string + ld c, e + + ld (hl), ' ' + ld d, h + ld e, l + inc de + dec bc + ld a, b + or c + jr z, __CONT2 + + ; At this point HL = DE = Start of Write zone in a$ + ; BC = Number of chars to write + + ldir + +__CONT2: + + pop bc ; Recovers Length of string to copy + exx + ex de, hl ; HL = Source, DE = Target + + ld a, h + or l + jp z, __FREE_STR ; Return if B$ is NULL + + ld c, (hl) + inc hl + ld b, (hl) + inc hl + + ld a, b + or c + jp z, __FREE_STR ; Return if len(b$) = 0 + + ; Now if len(b$) < len(char to copy), copy only len(b$) chars + + push de + push hl + push bc + exx + pop hl ; LEN (b$) + or a + sbc hl, bc + add hl, bc + jr nc, __CONT1 + + ; If len(b$) < len(to copy) + ld b, h ; BC = len(to copy) + ld c, l + +__CONT1: + pop hl + pop de + ldir ; Copy b$ into a$(x to y) + + exx + ex de, hl + +__FREE_STR0: + ex de, hl + +__FREE_STR: + ex af, af' + or a ; If not 0, free + jp nz, __MEM_FREE + ret + + ENDP + +#line 36 "id_substr_eq_expr.bas" +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 69 "alloc.asm" + + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 37 "id_substr_eq_expr.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 00, 00 +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/id_substr_eq_expr.bas b/tests/functional/id_substr_eq_expr.bas new file mode 100644 index 000000000..e5c1aab51 --- /dev/null +++ b/tests/functional/id_substr_eq_expr.bas @@ -0,0 +1,3 @@ + +a$(1 TO 5) = "Hello" + diff --git a/tests/functional/letarrstr_substr0.asm b/tests/functional/letarrstr_substr0.asm new file mode 100644 index 000000000..7ec334680 --- /dev/null +++ b/tests/functional/letarrstr_substr0.asm @@ -0,0 +1,828 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld hl, (_a + 5) + call __LOADSTR + push hl + ld hl, 2 + push hl + ld hl, 4 + push hl + ld a, 1 + call __STRSLICE + ex de, hl + ld hl, _b + call __STORE_STR2 + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 69 "alloc.asm" +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 70 "alloc.asm" + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 30 "letarrstr_substr0.bas" +#line 1 "storestr2.asm" + + ; Similar to __STORE_STR, but this one is called when + ; the value of B$ if already duplicated onto the stack. + ; So we needn't call STRASSING to create a duplication + ; HL = address of string memory variable + ; DE = address of 2n string. It just copies DE into (HL) + ; freeing (HL) previously. + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 9 "storestr2.asm" + +__PISTORE_STR2: ; Indirect store temporary string at (IX + BC) + push ix + pop hl + add hl, bc + +__ISTORE_STR2: + ld c, (hl) ; Dereferences HL + inc hl + ld h, (hl) + ld l, c ; HL = *HL (real string variable address) + +__STORE_STR2: + push hl + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = *HL (real string address) + + push de + call __MEM_FREE + pop de + + pop hl + ld (hl), e + inc hl + ld (hl), d + dec hl ; HL points to mem address variable. This might be useful in the future. + + ret + +#line 31 "letarrstr_substr0.bas" +#line 1 "strslice.asm" + + ; String slicing library + ; HL = Str pointer + ; DE = String start + ; BC = String character end + ; A register => 0 => the HL pointer wont' be freed from the HEAP + ; e.g. a$(5 TO 10) => HL = a$; DE = 5; BC = 10 + + ; This implements a$(X to Y) being X and Y first and + ; last characters respectively. If X > Y, NULL is returned + + ; Otherwise returns a pointer to a$ FROM X to Y (starting from 0) + ; if Y > len(a$), then a$ will be padded with spaces (reallocating + ; it in dynamic memory if needed). Returns pointer (HL) to resulting + ; string. NULL (0) if no memory for padding. + ; + +#line 1 "strlen.asm" + + ; Returns len if a string + ; If a string is NULL, its len is also 0 + ; Result returned in HL + +__STRLEN: ; Direct FASTCALL entry + ld a, h + or l + ret z + + ld a, (hl) + inc hl + ld h, (hl) ; LEN(str) in HL + ld l, a + ret + + +#line 18 "strslice.asm" + + + +__STRSLICE: ; Callee entry + pop hl ; Return ADDRESS + pop bc ; Last char pos + pop de ; 1st char pos + ex (sp), hl ; CALLEE. -> String start + +__STRSLICE_FAST: ; __FASTCALL__ Entry + PROC + + LOCAL __CONT + LOCAL __EMPTY + LOCAL __FREE_ON_EXIT + + push hl ; Stores original HL pointer to be recovered on exit + ex af, af' ; Saves A register for later + + push hl + call __STRLEN + inc bc ; Last character position + 1 (string starts from 0) + or a + sbc hl, bc ; Compares length with last char position + jr nc, __CONT ; If Carry => We must copy to end of string + add hl, bc ; Restore back original LEN(a$) in HL + ld b, h + ld c, l ; Copy to the end of str + ccf ; Clears Carry flag for next subtraction + +__CONT: + ld h, b + ld l, c ; HL = Last char position to copy (1 for char 0, 2 for char 1, etc) + sbc hl, de ; HL = LEN(a$) - DE => Number of chars to copy + jr z, __EMPTY ; 0 Chars to copy => Return HL = 0 (NULL STR) + jr c, __EMPTY ; If Carry => Nothing to return (NULL STR) + + ld b, h + ld c, l ; BC = Number of chars to copy + inc bc + inc bc ; +2 bytes for string length number + + push bc + push de + call __MEM_ALLOC + pop de + pop bc + ld a, h + or l + jr z, __EMPTY ; Return if NULL (no memory) + + dec bc + dec bc ; Number of chars to copy (Len of slice) + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Stores new string length + + ex (sp), hl ; Pointer to A$ now in HL; Pointer to new string chars in Stack + inc hl + inc hl ; Skip string length + add hl, de ; Were to start from A$ + pop de ; Start of new string chars + push de ; Stores it again + ldir ; Copies BC chars + pop de + dec de + dec de ; Points to String LEN start + ex de, hl ; Returns it in HL + jr __FREE_ON_EXIT + +__EMPTY: ; Return NULL (empty) string + pop hl + ld hl, 0 ; Return NULL + + +__FREE_ON_EXIT: + ex af, af' ; Recover original A register + ex (sp), hl ; Original HL pointer + + or a + call nz, __MEM_FREE + + pop hl ; Recover result + ret + + ENDP + +#line 32 "letarrstr_substr0.bas" + +ZXBASIC_USER_DATA: +_b: + DEFB 00, 00 +_a: + DEFW 0000h + DEFB 02h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/letarrstr_substr0.bas b/tests/functional/letarrstr_substr0.bas new file mode 100644 index 000000000..df863464b --- /dev/null +++ b/tests/functional/letarrstr_substr0.bas @@ -0,0 +1,4 @@ +DIM a$(5) + +b$ = a$(1)(2 TO 4) 'OK + diff --git a/tests/functional/line_macro.asm b/tests/functional/line_macro.asm new file mode 100644 index 000000000..d13b1cc4e --- /dev/null +++ b/tests/functional/line_macro.asm @@ -0,0 +1,39 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, 5 + ld (_a), hl + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_a: + DEFB 00, 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/line_macro.bas b/tests/functional/line_macro.bas new file mode 100644 index 000000000..a32901cb7 --- /dev/null +++ b/tests/functional/line_macro.bas @@ -0,0 +1,6 @@ + + +DIM a as Uinteger + +LET a = __LINE__ + diff --git a/tests/functional/string_substr.asm b/tests/functional/string_substr.asm new file mode 100644 index 000000000..a3d5cc5bb --- /dev/null +++ b/tests/functional/string_substr.asm @@ -0,0 +1,779 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld hl, __LABEL0 + push hl + ld a, (_i) + inc a + ld l, a + ld h, 0 + push hl + ld hl, 65534 + push hl + xor a + call __STRSLICE + ex de, hl + ld hl, _a + call __STORE_STR2 + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__LABEL0: + DEFW 0006h + DEFB 53h + DEFB 54h + DEFB 52h + DEFB 49h + DEFB 4Eh + DEFB 47h +#line 1 "storestr2.asm" + + ; Similar to __STORE_STR, but this one is called when + ; the value of B$ if already duplicated onto the stack. + ; So we needn't call STRASSING to create a duplication + ; HL = address of string memory variable + ; DE = address of 2n string. It just copies DE into (HL) + ; freeing (HL) previously. + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 9 "storestr2.asm" + +__PISTORE_STR2: ; Indirect store temporary string at (IX + BC) + push ix + pop hl + add hl, bc + +__ISTORE_STR2: + ld c, (hl) ; Dereferences HL + inc hl + ld h, (hl) + ld l, c ; HL = *HL (real string variable address) + +__STORE_STR2: + push hl + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = *HL (real string address) + + push de + call __MEM_FREE + pop de + + pop hl + ld (hl), e + inc hl + ld (hl), d + dec hl ; HL points to mem address variable. This might be useful in the future. + + ret + +#line 40 "string_substr.bas" +#line 1 "strslice.asm" + + ; String slicing library + ; HL = Str pointer + ; DE = String start + ; BC = String character end + ; A register => 0 => the HL pointer wont' be freed from the HEAP + ; e.g. a$(5 TO 10) => HL = a$; DE = 5; BC = 10 + + ; This implements a$(X to Y) being X and Y first and + ; last characters respectively. If X > Y, NULL is returned + + ; Otherwise returns a pointer to a$ FROM X to Y (starting from 0) + ; if Y > len(a$), then a$ will be padded with spaces (reallocating + ; it in dynamic memory if needed). Returns pointer (HL) to resulting + ; string. NULL (0) if no memory for padding. + ; + +#line 1 "strlen.asm" + + ; Returns len if a string + ; If a string is NULL, its len is also 0 + ; Result returned in HL + +__STRLEN: ; Direct FASTCALL entry + ld a, h + or l + ret z + + ld a, (hl) + inc hl + ld h, (hl) ; LEN(str) in HL + ld l, a + ret + + +#line 18 "strslice.asm" +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 69 "alloc.asm" + + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 19 "strslice.asm" + + +__STRSLICE: ; Callee entry + pop hl ; Return ADDRESS + pop bc ; Last char pos + pop de ; 1st char pos + ex (sp), hl ; CALLEE. -> String start + +__STRSLICE_FAST: ; __FASTCALL__ Entry + PROC + + LOCAL __CONT + LOCAL __EMPTY + LOCAL __FREE_ON_EXIT + + push hl ; Stores original HL pointer to be recovered on exit + ex af, af' ; Saves A register for later + + push hl + call __STRLEN + inc bc ; Last character position + 1 (string starts from 0) + or a + sbc hl, bc ; Compares length with last char position + jr nc, __CONT ; If Carry => We must copy to end of string + add hl, bc ; Restore back original LEN(a$) in HL + ld b, h + ld c, l ; Copy to the end of str + ccf ; Clears Carry flag for next subtraction + +__CONT: + ld h, b + ld l, c ; HL = Last char position to copy (1 for char 0, 2 for char 1, etc) + sbc hl, de ; HL = LEN(a$) - DE => Number of chars to copy + jr z, __EMPTY ; 0 Chars to copy => Return HL = 0 (NULL STR) + jr c, __EMPTY ; If Carry => Nothing to return (NULL STR) + + ld b, h + ld c, l ; BC = Number of chars to copy + inc bc + inc bc ; +2 bytes for string length number + + push bc + push de + call __MEM_ALLOC + pop de + pop bc + ld a, h + or l + jr z, __EMPTY ; Return if NULL (no memory) + + dec bc + dec bc ; Number of chars to copy (Len of slice) + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Stores new string length + + ex (sp), hl ; Pointer to A$ now in HL; Pointer to new string chars in Stack + inc hl + inc hl ; Skip string length + add hl, de ; Were to start from A$ + pop de ; Start of new string chars + push de ; Stores it again + ldir ; Copies BC chars + pop de + dec de + dec de ; Points to String LEN start + ex de, hl ; Returns it in HL + jr __FREE_ON_EXIT + +__EMPTY: ; Return NULL (empty) string + pop hl + ld hl, 0 ; Return NULL + + +__FREE_ON_EXIT: + ex af, af' ; Recover original A register + ex (sp), hl ; Original HL pointer + + or a + call nz, __MEM_FREE + + pop hl ; Recover result + ret + + ENDP + +#line 41 "string_substr.bas" + +ZXBASIC_USER_DATA: +_i: + DEFB 00 +_a: + DEFB 00, 00 +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/string_substr.bas b/tests/functional/string_substr.bas new file mode 100644 index 000000000..3bb9f004b --- /dev/null +++ b/tests/functional/string_substr.bas @@ -0,0 +1,3 @@ +DIM i As UByte +LET a$ = "STRING"(i + 1 TO) + diff --git a/tests/functional/substr_empty.asm b/tests/functional/substr_empty.asm new file mode 100644 index 000000000..aa668fe9e --- /dev/null +++ b/tests/functional/substr_empty.asm @@ -0,0 +1,896 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld de, (_b) + ld hl, _a + call __STORE_STR + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "storestr.asm" + +; vim:ts=4:et:sw=4 + ; Stores value of current string pointed by DE register into address pointed by HL + ; Returns DE = Address pointer (&a$) + ; Returns HL = HL (b$ => might be needed later to free it from the heap) + ; + ; e.g. => HL = _variableName (DIM _variableName$) + ; DE = Address into the HEAP + ; + ; This function will resize (REALLOC) the space pointed by HL + ; before copying the content of b$ into a$ + + +#line 1 "strcpy.asm" + +#line 1 "realloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 70 "realloc.asm" +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 70 "alloc.asm" + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 71 "realloc.asm" +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 72 "realloc.asm" + + + ; --------------------------------------------------------------------- + ; MEM_REALLOC + ; Reallocates a block of memory in the heap. + ; + ; Parameters + ; HL = Pointer to the original block + ; BC = New Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; +; Notes: + ; If BC = 0, the block is freed, otherwise + ; the content of the original block is copied to the new one, and + ; the new size is adjusted. If BC < original length, the content + ; will be truncated. Otherwise, extra block content might contain + ; memory garbage. + ; + ; --------------------------------------------------------------------- +__REALLOC: ; Reallocates block pointed by HL, with new length BC + PROC + + LOCAL __REALLOC_END + + ld a, h + or l + jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc + + ld e, (hl) + inc hl + ld d, (hl) ; DE = First 2 bytes of HL block + + push hl + exx + pop de + inc de ; DE' <- HL + 2 + exx ; DE' <- HL (Saves current pointer into DE') + + dec hl ; HL = Block start + + push de + push bc + call __MEM_FREE ; Frees current block + pop bc + push bc + call __MEM_ALLOC ; Gets a new block of length BC + pop bc + pop de + + ld a, h + or l + ret z ; Return if HL == NULL (No memory) + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Recovers first 2 bytes in HL + + dec bc + dec bc ; BC = BC - 2 (Two bytes copied) + + ld a, b + or c + jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) + + exx + push de + exx + pop de ; DE <- DE' ; Start of remaining block + + push hl ; Saves current Block + 2 start + ex de, hl ; Exchanges them: DE is destiny block + ldir ; Copies BC Bytes + pop hl ; Recovers Block + 2 start + +__REALLOC_END: + + dec hl ; Set HL + dec hl ; To begin of block + ret + + ENDP + +#line 2 "strcpy.asm" + + ; String library + + +__STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) + PROC + + LOCAL __STRREALLOC + LOCAL __STRCONTINUE + LOCAL __B_IS_NULL + LOCAL __NOTHING_TO_COPY + + ld b, d + ld c, e + ld a, b + or c + jr z, __B_IS_NULL + + ex de, hl + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(b$) + ex de, hl ; DE = &b$ + +__B_IS_NULL: ; Jumps here if B$ pointer is NULL + inc bc + inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) + + push de + push hl + + ld a, h + or l + jr z, __STRREALLOC + + dec hl + ld d, (hl) + dec hl + ld e, (hl) ; DE = MEMBLOCKSIZE(a$) + dec de + dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) + + ld h, b + ld l, c ; HL = LEN(b$) + 2 => Minimum block size required + ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 + + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) + sbc hl, de ; Carry if len(b$) > Blocklen(a$) + jr c, __STRREALLOC ; No need to realloc + ; Need to reallocate at least to len(b$) + 2 + ex de, hl ; DE = Remaining bytes in a$ mem block. + ld hl, 4 + sbc hl, de ; if remaining bytes < 4 we can continue + jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes + +__STRREALLOC: + pop hl + call __REALLOC ; Returns in HL a new pointer with BC bytes allocated + push hl + +__STRCONTINUE: ; Pops hl and de SWAPPED + pop de ; DE = &a$ + pop hl ; HL = &b$ + + ld a, d ; Return if not enough memory for new length + or e + ret z ; Return if DE == NULL (0) + +__STRCPY: ; Copies string pointed by HL into string pointed by DE + ; Returns DE as HL (new pointer) + ld a, h + or l + jr z, __NOTHING_TO_COPY + ld c, (hl) + inc hl + ld b, (hl) + dec hl + inc bc + inc bc + push de + ldir + pop hl + ret + +__NOTHING_TO_COPY: + ex de, hl + ld (hl), e + inc hl + ld (hl), d + dec hl + ret + + ENDP + +#line 14 "storestr.asm" + +__PISTORE_STR: ; Indirect assignement at (IX + BC) + push ix + pop hl + add hl, bc + +__ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + +__STORE_STR: + push de ; Pointer to b$ + push hl ; Array pointer to variable memory address + + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation + ex de, hl ; DE = new address of a$ + pop hl ; Recover variable memory address pointer + + ld (hl), e + inc hl + ld (hl), d ; Stores a$ ptr into elemem ptr + + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) + ret + +#line 21 "substr_empty.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 00, 00 +_b: + DEFB 00, 00 +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/substr_empty.bas b/tests/functional/substr_empty.bas new file mode 100644 index 000000000..00311e71d --- /dev/null +++ b/tests/functional/substr_empty.bas @@ -0,0 +1,3 @@ + +a$=b$(TO) + diff --git a/tests/functional/substr_empty2.asm b/tests/functional/substr_empty2.asm new file mode 100644 index 000000000..6f7486df2 --- /dev/null +++ b/tests/functional/substr_empty2.asm @@ -0,0 +1,902 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld de, __LABEL0 + ld hl, _a + call __STORE_STR + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__LABEL0: + DEFW 0006h + DEFB 53h + DEFB 54h + DEFB 52h + DEFB 49h + DEFB 4Eh + DEFB 47h +#line 1 "storestr.asm" + +; vim:ts=4:et:sw=4 + ; Stores value of current string pointed by DE register into address pointed by HL + ; Returns DE = Address pointer (&a$) + ; Returns HL = HL (b$ => might be needed later to free it from the heap) + ; + ; e.g. => HL = _variableName (DIM _variableName$) + ; DE = Address into the HEAP + ; + ; This function will resize (REALLOC) the space pointed by HL + ; before copying the content of b$ into a$ + + +#line 1 "strcpy.asm" + +#line 1 "realloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 70 "realloc.asm" +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 70 "alloc.asm" + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 71 "realloc.asm" +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 72 "realloc.asm" + + + ; --------------------------------------------------------------------- + ; MEM_REALLOC + ; Reallocates a block of memory in the heap. + ; + ; Parameters + ; HL = Pointer to the original block + ; BC = New Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; +; Notes: + ; If BC = 0, the block is freed, otherwise + ; the content of the original block is copied to the new one, and + ; the new size is adjusted. If BC < original length, the content + ; will be truncated. Otherwise, extra block content might contain + ; memory garbage. + ; + ; --------------------------------------------------------------------- +__REALLOC: ; Reallocates block pointed by HL, with new length BC + PROC + + LOCAL __REALLOC_END + + ld a, h + or l + jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc + + ld e, (hl) + inc hl + ld d, (hl) ; DE = First 2 bytes of HL block + + push hl + exx + pop de + inc de ; DE' <- HL + 2 + exx ; DE' <- HL (Saves current pointer into DE') + + dec hl ; HL = Block start + + push de + push bc + call __MEM_FREE ; Frees current block + pop bc + push bc + call __MEM_ALLOC ; Gets a new block of length BC + pop bc + pop de + + ld a, h + or l + ret z ; Return if HL == NULL (No memory) + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Recovers first 2 bytes in HL + + dec bc + dec bc ; BC = BC - 2 (Two bytes copied) + + ld a, b + or c + jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) + + exx + push de + exx + pop de ; DE <- DE' ; Start of remaining block + + push hl ; Saves current Block + 2 start + ex de, hl ; Exchanges them: DE is destiny block + ldir ; Copies BC Bytes + pop hl ; Recovers Block + 2 start + +__REALLOC_END: + + dec hl ; Set HL + dec hl ; To begin of block + ret + + ENDP + +#line 2 "strcpy.asm" + + ; String library + + +__STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) + PROC + + LOCAL __STRREALLOC + LOCAL __STRCONTINUE + LOCAL __B_IS_NULL + LOCAL __NOTHING_TO_COPY + + ld b, d + ld c, e + ld a, b + or c + jr z, __B_IS_NULL + + ex de, hl + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(b$) + ex de, hl ; DE = &b$ + +__B_IS_NULL: ; Jumps here if B$ pointer is NULL + inc bc + inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) + + push de + push hl + + ld a, h + or l + jr z, __STRREALLOC + + dec hl + ld d, (hl) + dec hl + ld e, (hl) ; DE = MEMBLOCKSIZE(a$) + dec de + dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) + + ld h, b + ld l, c ; HL = LEN(b$) + 2 => Minimum block size required + ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 + + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) + sbc hl, de ; Carry if len(b$) > Blocklen(a$) + jr c, __STRREALLOC ; No need to realloc + ; Need to reallocate at least to len(b$) + 2 + ex de, hl ; DE = Remaining bytes in a$ mem block. + ld hl, 4 + sbc hl, de ; if remaining bytes < 4 we can continue + jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes + +__STRREALLOC: + pop hl + call __REALLOC ; Returns in HL a new pointer with BC bytes allocated + push hl + +__STRCONTINUE: ; Pops hl and de SWAPPED + pop de ; DE = &a$ + pop hl ; HL = &b$ + + ld a, d ; Return if not enough memory for new length + or e + ret z ; Return if DE == NULL (0) + +__STRCPY: ; Copies string pointed by HL into string pointed by DE + ; Returns DE as HL (new pointer) + ld a, h + or l + jr z, __NOTHING_TO_COPY + ld c, (hl) + inc hl + ld b, (hl) + dec hl + inc bc + inc bc + push de + ldir + pop hl + ret + +__NOTHING_TO_COPY: + ex de, hl + ld (hl), e + inc hl + ld (hl), d + dec hl + ret + + ENDP + +#line 14 "storestr.asm" + +__PISTORE_STR: ; Indirect assignement at (IX + BC) + push ix + pop hl + add hl, bc + +__ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + +__STORE_STR: + push de ; Pointer to b$ + push hl ; Array pointer to variable memory address + + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation + ex de, hl ; DE = new address of a$ + pop hl ; Recover variable memory address pointer + + ld (hl), e + inc hl + ld (hl), d ; Stores a$ ptr into elemem ptr + + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) + ret + +#line 29 "substr_empty2.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 00, 00 +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/substr_empty2.bas b/tests/functional/substr_empty2.bas new file mode 100644 index 000000000..a045f54ca --- /dev/null +++ b/tests/functional/substr_empty2.bas @@ -0,0 +1,2 @@ +a$="STRING"() + diff --git a/tests/functional/substr_expr2.asm b/tests/functional/substr_expr2.asm new file mode 100644 index 000000000..b212d3477 --- /dev/null +++ b/tests/functional/substr_expr2.asm @@ -0,0 +1,780 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld hl, __LABEL0 + push hl + ld hl, (_i) + ld de, 5 + add hl, de + push hl + ld hl, (_i) + ld de, 5 + add hl, de + push hl + xor a + call __STRSLICE + ex de, hl + ld hl, _a + call __STORE_STR2 + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__LABEL0: + DEFW 0006h + DEFB 53h + DEFB 54h + DEFB 52h + DEFB 49h + DEFB 4Eh + DEFB 47h +#line 1 "storestr2.asm" + + ; Similar to __STORE_STR, but this one is called when + ; the value of B$ if already duplicated onto the stack. + ; So we needn't call STRASSING to create a duplication + ; HL = address of string memory variable + ; DE = address of 2n string. It just copies DE into (HL) + ; freeing (HL) previously. + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 9 "storestr2.asm" + +__PISTORE_STR2: ; Indirect store temporary string at (IX + BC) + push ix + pop hl + add hl, bc + +__ISTORE_STR2: + ld c, (hl) ; Dereferences HL + inc hl + ld h, (hl) + ld l, c ; HL = *HL (real string variable address) + +__STORE_STR2: + push hl + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = *HL (real string address) + + push de + call __MEM_FREE + pop de + + pop hl + ld (hl), e + inc hl + ld (hl), d + dec hl ; HL points to mem address variable. This might be useful in the future. + + ret + +#line 41 "substr_expr2.bas" +#line 1 "strslice.asm" + + ; String slicing library + ; HL = Str pointer + ; DE = String start + ; BC = String character end + ; A register => 0 => the HL pointer wont' be freed from the HEAP + ; e.g. a$(5 TO 10) => HL = a$; DE = 5; BC = 10 + + ; This implements a$(X to Y) being X and Y first and + ; last characters respectively. If X > Y, NULL is returned + + ; Otherwise returns a pointer to a$ FROM X to Y (starting from 0) + ; if Y > len(a$), then a$ will be padded with spaces (reallocating + ; it in dynamic memory if needed). Returns pointer (HL) to resulting + ; string. NULL (0) if no memory for padding. + ; + +#line 1 "strlen.asm" + + ; Returns len if a string + ; If a string is NULL, its len is also 0 + ; Result returned in HL + +__STRLEN: ; Direct FASTCALL entry + ld a, h + or l + ret z + + ld a, (hl) + inc hl + ld h, (hl) ; LEN(str) in HL + ld l, a + ret + + +#line 18 "strslice.asm" +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 69 "alloc.asm" + + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 19 "strslice.asm" + + +__STRSLICE: ; Callee entry + pop hl ; Return ADDRESS + pop bc ; Last char pos + pop de ; 1st char pos + ex (sp), hl ; CALLEE. -> String start + +__STRSLICE_FAST: ; __FASTCALL__ Entry + PROC + + LOCAL __CONT + LOCAL __EMPTY + LOCAL __FREE_ON_EXIT + + push hl ; Stores original HL pointer to be recovered on exit + ex af, af' ; Saves A register for later + + push hl + call __STRLEN + inc bc ; Last character position + 1 (string starts from 0) + or a + sbc hl, bc ; Compares length with last char position + jr nc, __CONT ; If Carry => We must copy to end of string + add hl, bc ; Restore back original LEN(a$) in HL + ld b, h + ld c, l ; Copy to the end of str + ccf ; Clears Carry flag for next subtraction + +__CONT: + ld h, b + ld l, c ; HL = Last char position to copy (1 for char 0, 2 for char 1, etc) + sbc hl, de ; HL = LEN(a$) - DE => Number of chars to copy + jr z, __EMPTY ; 0 Chars to copy => Return HL = 0 (NULL STR) + jr c, __EMPTY ; If Carry => Nothing to return (NULL STR) + + ld b, h + ld c, l ; BC = Number of chars to copy + inc bc + inc bc ; +2 bytes for string length number + + push bc + push de + call __MEM_ALLOC + pop de + pop bc + ld a, h + or l + jr z, __EMPTY ; Return if NULL (no memory) + + dec bc + dec bc ; Number of chars to copy (Len of slice) + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Stores new string length + + ex (sp), hl ; Pointer to A$ now in HL; Pointer to new string chars in Stack + inc hl + inc hl ; Skip string length + add hl, de ; Were to start from A$ + pop de ; Start of new string chars + push de ; Stores it again + ldir ; Copies BC chars + pop de + dec de + dec de ; Points to String LEN start + ex de, hl ; Returns it in HL + jr __FREE_ON_EXIT + +__EMPTY: ; Return NULL (empty) string + pop hl + ld hl, 0 ; Return NULL + + +__FREE_ON_EXIT: + ex af, af' ; Recover original A register + ex (sp), hl ; Original HL pointer + + or a + call nz, __MEM_FREE + + pop hl ; Recover result + ret + + ENDP + +#line 42 "substr_expr2.bas" + +ZXBASIC_USER_DATA: +_i: + DEFB 00, 00 +_a: + DEFB 00, 00 +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/substr_expr2.bas b/tests/functional/substr_expr2.bas new file mode 100644 index 000000000..b7eaa9eed --- /dev/null +++ b/tests/functional/substr_expr2.bas @@ -0,0 +1,4 @@ + +DIM i As Uinteger +LET a$ = "STRING"(5 + i) + diff --git a/tests/functional/test_errmsg.txt b/tests/functional/test_errmsg.txt index ff105f384..7f83c2115 100644 --- a/tests/functional/test_errmsg.txt +++ b/tests/functional/test_errmsg.txt @@ -117,4 +117,6 @@ asmerror2.asm:2: Syntax error. Unexpected end of line [NEWLINE] llb.bas:3: Undeclared function "f$" >>> process_file('substr_expr_err.bas') substr_expr_err.bas:3: Expected a string type expression. Got byte type instead +>>> process_file('dup_func_decl.bas') +dup_func_decl.bas:5: duplicated declaration for function 'f' From dcf6ae55a18c5ed75f46a6667246f319e259463f Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Thu, 5 Apr 2018 23:56:53 +0200 Subject: [PATCH 198/247] code clean up --- symbols/arrayaccess.py | 20 ++++++-------------- zxbparser.py | 4 ---- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/symbols/arrayaccess.py b/symbols/arrayaccess.py index 5f0d769bd..ba8d34920 100644 --- a/symbols/arrayaccess.py +++ b/symbols/arrayaccess.py @@ -25,7 +25,7 @@ class SymbolARRAYACCESS(SymbolCALL): - ''' Defines an array access. It's pretty much like a function call + """ Defines an array access. It's pretty much like a function call (e.g. A(1, 2) could be an array access or a function call, depending on context). So we derive this class from SymbolCall @@ -36,7 +36,7 @@ class SymbolARRAYACCESS(SymbolCALL): Parameters: entry will be the symboltable entry. Arglist a SymbolARGLIST instance. - ''' + """ def __init__(self, entry, arglist, lineno): SymbolCALL.__init__(self, entry, arglist, lineno) @@ -71,13 +71,13 @@ def scope(self): @property def offset(self): - ''' If this is a constant access (e.g. A(1)) + """ If this is a constant access (e.g. A(1)) return the offset in bytes from the beginning of the variable in memory. Otherwise, if it's not constant (e.g. A(i)) returns None - ''' + """ offset = 0 # Now we must typecast each argument to a u16 (POINTER) type # i is the dimension ith index, b is the bound @@ -97,17 +97,9 @@ def offset(self): @classmethod def make_node(cls, id_, arglist, lineno): - ''' Creates an array access. A(x1, x2, ..., xn) - ''' - assert isinstance(arglist, SymbolARGLIST) - """ - check = gl.SYMBOL_TABLE.check_class(id_, CLASS.array, lineno) - if not check: - return None - - if not gl.SYMBOL_TABLE.check_is_declared(id_, lineno, 'array'): - return None + """ Creates an array access. A(x1, x2, ..., xn) """ + assert isinstance(arglist, SymbolARGLIST) variable = gl.SYMBOL_TABLE.access_array(id_, lineno) if variable is None: return None diff --git a/zxbparser.py b/zxbparser.py index a16dc3178..9dbaf966e 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -1043,12 +1043,8 @@ def p_arr_assignment(p): return # There were errors p[0] = None - # api.check.check_is_declared_strict(p.lineno(i - 1), q[0], classname='array') - entry = SYMBOL_TABLE.access_call(q[0], p.lineno(i - 1)) if entry is None: - # variable = SYMBOL_TABLE.make_var(q[0], p.lineno(1), TYPE.string) - # entry = SYMBOL_TABLE.get_id_entry(q[0]) return arr = make_array_access(q[0], p.lineno(i), q[1]) From 00c789ab5ccba2d72e685267210435abeb3f0f0b Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 8 Apr 2018 19:04:45 +0200 Subject: [PATCH 199/247] improvement: optimize print str for arr elements When printing an element of an array of string, there's no need to load it temporarily. --- arch/zx48k/backend/__init__.py | 15 + tests/functional/print_arrstr.asm | 2122 +++++++++++++++++++++++++++++ tests/functional/print_arrstr.bas | 5 + 3 files changed, 2142 insertions(+) create mode 100644 tests/functional/print_arrstr.asm create mode 100644 tests/functional/print_arrstr.bas diff --git a/arch/zx48k/backend/__init__.py b/arch/zx48k/backend/__init__.py index c75be5b5e..02e60806f 100644 --- a/arch/zx48k/backend/__init__.py +++ b/arch/zx48k/backend/__init__.py @@ -129,6 +129,7 @@ OPT29 = True OPT30 = True OPT31 = True +OPT32 = True # Label RegExp RE_LABEL = re.compile('^[ \t]*[a-zA-Z_][_a-zA-Z\d]*:') @@ -2718,6 +2719,20 @@ def output_join(output, new_chunk): changed = True continue + # Converts: + # call __LOADSTR + # ld a, 1 + # call __PRINSTR + # Into: + # xor a + # call __PRINTSTR + if OPT32 and i0 == 'call' and o0[0] == '__LOADSTR' and i1 == 'ld' and tuple(o1) == ('a', '1') and \ + i2 == 'call' and o2[0] == '__PRINTSTR': + output.pop(-2) + output[-1] = 'xor a' + changed = True + continue + changed, new_chunk = optiblock(new_chunk) output.extend(new_chunk) diff --git a/tests/functional/print_arrstr.asm b/tests/functional/print_arrstr.asm new file mode 100644 index 000000000..51eba47a9 --- /dev/null +++ b/tests/functional/print_arrstr.asm @@ -0,0 +1,2122 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + call __PRINT_INIT + ld de, __LABEL0 + ld hl, _a + 13 + call __STORE_STR + ld hl, (_a + 13) + xor a + call __PRINTSTR + call PRINT_EOL + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__LABEL0: + DEFW 000Bh + DEFB 48h + DEFB 45h + DEFB 4Ch + DEFB 4Ch + DEFB 4Fh + DEFB 20h + DEFB 57h + DEFB 4Fh + DEFB 52h + DEFB 4Ch + DEFB 44h +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 69 "alloc.asm" +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 70 "alloc.asm" + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 38 "print_arrstr.bas" +#line 1 "print.asm" + +; vim:ts=4:sw=4:et: + ; PRINT command routine + ; Does not print attribute. Use PRINT_STR or PRINT_NUM for that + +#line 1 "sposn.asm" + + ; Printing positioning library. + PROC + LOCAL ECHO_E + +__LOAD_S_POSN: ; Loads into DE current ROW, COL print position from S_POSN mem var. + ld de, (S_POSN) + ld hl, (MAXX) + or a + sbc hl, de + ex de, hl + ret + + +__SAVE_S_POSN: ; Saves ROW, COL from DE into S_POSN mem var. + ld hl, (MAXX) + or a + sbc hl, de + ld (S_POSN), hl ; saves it again + ret + + + ECHO_E EQU 23682 + MAXX EQU ECHO_E ; Max X position + 1 + MAXY EQU MAXX + 1 ; Max Y position + 1 + + S_POSN EQU 23688 + POSX EQU S_POSN ; Current POS X + POSY EQU S_POSN + 1 ; Current POS Y + + ENDP + +#line 6 "print.asm" +#line 1 "cls.asm" + + ; JUMPS directly to spectrum CLS + ; This routine does not clear lower screen + + ;CLS EQU 0DAFh + + ; Our faster implementation + + + +CLS: + PROC + + LOCAL COORDS + LOCAL __CLS_SCR + LOCAL ATTR_P + LOCAL SCREEN + + ld hl, 0 + ld (COORDS), hl + ld hl, 1821h + ld (S_POSN), hl +__CLS_SCR: + ld hl, SCREEN + ld (hl), 0 + ld d, h + ld e, l + inc de + ld bc, 6144 + ldir + + ; Now clear attributes + + ld a, (ATTR_P) + ld (hl), a + ld bc, 767 + ldir + ret + + COORDS EQU 23677 + SCREEN EQU 16384 ; Default start of the screen (can be changed) + ATTR_P EQU 23693 + ;you can poke (SCREEN_SCRADDR) to change CLS, DRAW & PRINTing address + + SCREEN_ADDR EQU (__CLS_SCR + 1) ; Address used by print and other screen routines + ; to get the start of the screen + ENDP + +#line 7 "print.asm" +#line 1 "in_screen.asm" + + + + +__IN_SCREEN: + ; Returns NO carry if current coords (D, E) + ; are OUT of the screen limits (MAXX, MAXY) + + PROC + LOCAL __IN_SCREEN_ERR + + ld hl, MAXX + ld a, e + cp (hl) + jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + + ld a, d + inc hl + cp (hl) + ;; jr nc, __IN_SCREEN_ERR ; Do nothing and return if out of range + ;; ret + ret c ; Return if carry (OK) + +__IN_SCREEN_ERR: +__OUT_OF_SCREEN_ERR: + ; Jumps here if out of screen + ld a, ERROR_OutOfScreen + jp __STOP ; Saves error code and exits + + ENDP +#line 8 "print.asm" +#line 1 "table_jump.asm" + + +JUMP_HL_PLUS_2A: ; Does JP (HL + A*2) Modifies DE. Modifies A + add a, a + +JUMP_HL_PLUS_A: ; Does JP (HL + A) Modifies DE + ld e, a + ld d, 0 + +JUMP_HL_PLUS_DE: ; Does JP (HL + DE) + add hl, de + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl +CALL_HL: + jp (hl) + +#line 9 "print.asm" +#line 1 "ink.asm" + + ; Sets ink color in ATTR_P permanently +; Parameter: Paper color in A register + +#line 1 "const.asm" + + ; Global constants + + P_FLAG EQU 23697 + FLAGS2 EQU 23681 + ATTR_P EQU 23693 ; permanet ATTRIBUTES + ATTR_T EQU 23695 ; temporary ATTRIBUTES + CHARS EQU 23606 ; Pointer to ROM/RAM Charset + UDG EQU 23675 ; Pointer to UDG Charset + MEM0 EQU 5C92h ; Temporary memory buffer used by ROM chars + +#line 5 "ink.asm" + +INK: + PROC + LOCAL __SET_INK + LOCAL __SET_INK2 + + ld de, ATTR_P + +__SET_INK: + cp 8 + jr nz, __SET_INK2 + + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + or 7 ; Set bits 0,1,2 to enable transparency + ld (de), a + ret + +__SET_INK2: + ; Another entry. This will set the ink color at location pointer by DE + and 7 ; # Gets color mod 8 + ld b, a ; Saves the color + ld a, (de) + and 0F8h ; Clears previous value + or b + ld (de), a + inc de ; Points DE to MASK_T or MASK_P + ld a, (de) + and 0F8h ; Reset bits 0,1,2 sign to disable transparency + ld (de), a ; Store new attr + ret + + ; Sets the INK color passed in A register in the ATTR_T variable +INK_TMP: + ld de, ATTR_T + jp __SET_INK + + ENDP + +#line 10 "print.asm" +#line 1 "paper.asm" + + ; Sets paper color in ATTR_P permanently +; Parameter: Paper color in A register + + + +PAPER: + PROC + LOCAL __SET_PAPER + LOCAL __SET_PAPER2 + + ld de, ATTR_P + +__SET_PAPER: + cp 8 + jr nz, __SET_PAPER2 + inc de + ld a, (de) + or 038h + ld (de), a + ret + + ; Another entry. This will set the paper color at location pointer by DE +__SET_PAPER2: + and 7 ; # Remove + rlca + rlca + rlca ; a *= 8 + + ld b, a ; Saves the color + ld a, (de) + and 0C7h ; Clears previous value + or b + ld (de), a + inc de ; Points to MASK_T or MASK_P accordingly + ld a, (de) + and 0C7h ; Resets bits 3,4,5 + ld (de), a + ret + + + ; Sets the PAPER color passed in A register in the ATTR_T variable +PAPER_TMP: + ld de, ATTR_T + jp __SET_PAPER + ENDP + +#line 11 "print.asm" +#line 1 "flash.asm" + + ; Sets flash flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +FLASH: + ld de, ATTR_P +__SET_FLASH: + ; Another entry. This will set the flash flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + ld b, a ; Saves the color + ld a, (de) + and 07Fh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the FLASH flag passed in A register in the ATTR_T variable +FLASH_TMP: + ld de, ATTR_T + jr __SET_FLASH + +#line 12 "print.asm" +#line 1 "bright.asm" + + ; Sets bright flag in ATTR_P permanently +; Parameter: Paper color in A register + + + +BRIGHT: + ld de, ATTR_P + +__SET_BRIGHT: + ; Another entry. This will set the bright flag at location pointer by DE + and 1 ; # Convert to 0/1 + + rrca + rrca + ld b, a ; Saves the color + ld a, (de) + and 0BFh ; Clears previous value + or b + ld (de), a + ret + + + ; Sets the BRIGHT flag passed in A register in the ATTR_T variable +BRIGHT_TMP: + ld de, ATTR_T + jr __SET_BRIGHT + +#line 13 "print.asm" +#line 1 "over.asm" + + ; Sets OVER flag in P_FLAG permanently +; Parameter: OVER flag in bit 0 of A register +#line 1 "copy_attr.asm" + + + +#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" + + + +COPY_ATTR: + ; Just copies current permanent attribs to temporal attribs + ; and sets print mode + PROC + + LOCAL INVERSE1 + LOCAL __REFRESH_TMP + + INVERSE1 EQU 02Fh + + ld hl, (ATTR_P) + ld (ATTR_T), hl + + ld hl, FLAGS2 + call __REFRESH_TMP + + ld hl, P_FLAG + call __REFRESH_TMP + + +__SET_ATTR_MODE: ; Another entry to set print modes. A contains (P_FLAG) + + + LOCAL TABLE + LOCAL CONT2 + + rra ; Over bit to carry + ld a, (FLAGS2) + rla ; Over bit in bit 1, Over2 bit in bit 2 + and 3 ; Only bit 0 and 1 (OVER flag) + + ld c, a + ld b, 0 + + ld hl, TABLE + add hl, bc + ld a, (hl) + ld (PRINT_MODE), a + + ld hl, (P_FLAG) + xor a ; NOP -> INVERSE0 + bit 2, l + jr z, CONT2 + ld a, INVERSE1 ; CPL -> INVERSE1 + +CONT2: + ld (INVERSE_MODE), a + ret + +TABLE: + nop ; NORMAL MODE + xor (hl) ; OVER 1 MODE + and (hl) ; OVER 2 MODE + or (hl) ; OVER 3 MODE + +#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" + +__REFRESH_TMP: + ld a, (hl) + and 10101010b + ld c, a + rra + or c + ld (hl), a + ret + + ENDP + +#line 4 "over.asm" + + +OVER: + PROC + + ld c, a ; saves it for later + and 2 + ld hl, FLAGS2 + res 1, (HL) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 ; # Convert to 0/1 + add a, a; # Shift left 1 bit for permanent + + ld hl, P_FLAG + res 1, (hl) + or (hl) + ld (hl), a + ret + + ; Sets OVER flag in P_FLAG temporarily +OVER_TMP: + ld c, a ; saves it for later + and 2 ; gets bit 1; clears carry + rra + ld hl, FLAGS2 + res 0, (hl) + or (hl) + ld (hl), a + + ld a, c ; Recovers previous value + and 1 + ld hl, P_FLAG + res 0, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 14 "print.asm" +#line 1 "inverse.asm" + + ; Sets INVERSE flag in P_FLAG permanently +; Parameter: INVERSE flag in bit 0 of A register + + + +INVERSE: + PROC + + and 1 ; # Convert to 0/1 + add a, a; # Shift left 3 bits for permanent + add a, a + add a, a + ld hl, P_FLAG + res 3, (hl) + or (hl) + ld (hl), a + ret + + ; Sets INVERSE flag in P_FLAG temporarily +INVERSE_TMP: + and 1 + add a, a + add a, a; # Shift left 2 bits for temporary + ld hl, P_FLAG + res 2, (hl) + or (hl) + ld (hl), a + jp __SET_ATTR_MODE + + ENDP + +#line 15 "print.asm" +#line 1 "bold.asm" + + ; Sets BOLD flag in P_FLAG permanently +; Parameter: BOLD flag in bit 0 of A register + + +BOLD: + PROC + + and 1 + rlca + rlca + rlca + ld hl, FLAGS2 + res 3, (HL) + or (hl) + ld (hl), a + ret + + ; Sets BOLD flag in P_FLAG temporarily +BOLD_TMP: + and 1 + rlca + rlca + ld hl, FLAGS2 + res 2, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 16 "print.asm" +#line 1 "italic.asm" + + ; Sets ITALIC flag in P_FLAG permanently +; Parameter: ITALIC flag in bit 0 of A register + + +ITALIC: + PROC + + and 1 + rrca + rrca + rrca + ld hl, FLAGS2 + res 5, (HL) + or (hl) + ld (hl), a + ret + + ; Sets ITALIC flag in P_FLAG temporarily +ITALIC_TMP: + and 1 + rrca + rrca + rrca + rrca + ld hl, FLAGS2 + res 4, (hl) + or (hl) + ld (hl), a + ret + + ENDP + +#line 17 "print.asm" + +#line 1 "attr.asm" + + ; Attribute routines +; vim:ts=4:et:sw: + + + + + + + +__ATTR_ADDR: + ; calc start address in DE (as (32 * d) + e) + ; Contributed by Santiago Romero at http://www.speccy.org + ld h, 0 ; 7 T-States + ld a, d ; 4 T-States + add a, a ; a * 2 ; 4 T-States + add a, a ; a * 4 ; 4 T-States + ld l, a ; HL = A * 4 ; 4 T-States + + add hl, hl ; HL = A * 8 ; 15 T-States + add hl, hl ; HL = A * 16 ; 15 T-States + add hl, hl ; HL = A * 32 ; 15 T-States + + ld d, 18h ; DE = 6144 + E. Note: 6144 is the screen size (before attr zone) + add hl, de + + ld de, (SCREEN_ADDR) ; Adds the screen address + add hl, de + + ; Return current screen address in HL + ret + + + ; Sets the attribute at a given screen coordinate (D, E). + ; The attribute is taken from the ATTR_T memory variable + ; Used by PRINT routines +SET_ATTR: + + ; Checks for valid coords + call __IN_SCREEN + ret nc + +__SET_ATTR: + ; Internal __FASTCALL__ Entry used by printing routines + PROC + + call __ATTR_ADDR + ld de, (ATTR_T) ; E = ATTR_T, D = MASK_T + + ld a, d + and (hl) + ld c, a ; C = current screen color, masked + + ld a, d + cpl ; Negate mask + and e ; Mask current attributes + or c ; Mix them + ld (hl), a ; Store result in screen + + ret + + ENDP + + +#line 19 "print.asm" + + ; Putting a comment starting with @INIT
+ ; will make the compiler to add a CALL to
+ ; It is useful for initialization routines. + + +__PRINT_INIT: ; To be called before program starts (initializes library) + PROC + + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + + ld hl, 1821h + ld (MAXX), hl ; Sets current maxX and maxY + + xor a + ld (FLAGS2), a + + ret + + +__PRINTCHAR: ; Print character store in accumulator (A register) + ; Modifies H'L', B'C', A'F', D'E', A + + LOCAL PO_GR_1 + + LOCAL __PRCHAR + LOCAL __PRINT_CONT + LOCAL __PRINT_CONT2 + LOCAL __PRINT_JUMP + LOCAL __SRCADDR + LOCAL __PRINT_UDG + LOCAL __PRGRAPH + LOCAL __PRINT_START + + PRINT_JUMP_STATE EQU __PRINT_JUMP + 1 + +__PRINT_JUMP: + jp __PRINT_START ; Where to jump. If we print 22 (AT), next two calls jumps to AT1 and AT2 respectively + +__PRINT_START: + cp ' ' + jp c, __PRINT_SPECIAL ; Characters below ' ' are special ones + + exx ; Switch to alternative registers + ex af, af' ; Saves a value (char to print) for later + + call __LOAD_S_POSN + + ; At this point we have the new coord + ld hl, (SCREEN_ADDR) + + ld a, d + ld c, a ; Saves it for later + + and 0F8h ; Masks 3 lower bit ; zy + ld d, a + + ld a, c ; Recovers it + and 07h ; MOD 7 ; y1 + rrca + rrca + rrca + + or e + ld e, a + add hl, de ; HL = Screen address + DE + ex de, hl ; DE = Screen address + + ex af, af' + + cp 80h ; Is it an UDG or a ? + jp c, __SRCADDR + + cp 90h + jp nc, __PRINT_UDG + + ; Print a 8 bit pattern (80h to 8Fh) + + ld b, a + call PO_GR_1 ; This ROM routine will generate the bit pattern at MEM0 + ld hl, MEM0 + jp __PRGRAPH + + PO_GR_1 EQU 0B38h + +__PRINT_UDG: + sub 90h ; Sub ASC code + ld bc, (UDG) + jp __PRGRAPH0 + + __SOURCEADDR EQU (__SRCADDR + 1) ; Address of the pointer to chars source +__SRCADDR: + ld bc, (CHARS) + +__PRGRAPH0: + add a, a ; A = a * 2 (since a < 80h) ; Thanks to Metalbrain at http://foro.speccy.org + ld l, a + ld h, 0 ; HL = a * 2 (accumulator) + add hl, hl + add hl, hl ; HL = a * 8 + add hl, bc ; HL = CHARS address + +__PRGRAPH: + ex de, hl ; HL = Write Address, DE = CHARS address + bit 2, (iy + $47) + call nz, __BOLD + bit 4, (iy + $47) + call nz, __ITALIC + ld b, 8 ; 8 bytes per char +__PRCHAR: + ld a, (de) ; DE *must* be ALWAYS source, and HL destiny + +PRINT_MODE: ; Which operation is used to write on the screen + ; Set it with: + ; LD A, + ; LD (PRINT_MODE), A + ; + ; Available opertions: + ; NORMAL: 0h --> NOP ; OVER 0 + ; XOR : AEh --> XOR (HL) ; OVER 1 + ; OR : B6h --> OR (HL) ; PUTSPRITE + ; AND : A6h --> AND (HL) ; PUTMASK + nop ; + +INVERSE_MODE: ; 00 -> NOP -> INVERSE 0 + nop ; 2F -> CPL -> INVERSE 1 + + ld (hl), a + + inc de + inc h ; Next line + djnz __PRCHAR + + call __LOAD_S_POSN + push de + call __SET_ATTR + pop de + inc e ; COL = COL + 1 + ld hl, (MAXX) + ld a, e + dec l ; l = MAXX + cp l ; Lower than max? + jp c, __PRINT_CONT; Nothing to do + call __PRINT_EOL1 + exx ; counteracts __PRINT_EOL1 exx + jp __PRINT_CONT2 + +__PRINT_CONT: + call __SAVE_S_POSN + +__PRINT_CONT2: + exx + ret + + ; ------------- SPECIAL CHARS (< 32) ----------------- + +__PRINT_SPECIAL: ; Jumps here if it is a special char + exx + ld hl, __PRINT_TABLE + jp JUMP_HL_PLUS_2A + + +PRINT_EOL: ; Called WHENEVER there is no ";" at end of PRINT sentence + exx + +__PRINT_0Dh: ; Called WHEN printing CHR$(13) + call __LOAD_S_POSN + +__PRINT_EOL1: ; Another entry called from PRINT when next line required + ld e, 0 + +__PRINT_EOL2: + ld a, d + inc a + +__PRINT_AT1_END: + ld hl, (MAXY) + cp l + jr c, __PRINT_EOL_END ; Carry if (MAXY) < d + xor a + +__PRINT_EOL_END: + ld d, a + +__PRINT_AT2_END: + call __SAVE_S_POSN + exx + ret + +__PRINT_COM: + exx + push hl + push de + push bc + call PRINT_COMMA + pop bc + pop de + pop hl + ret + +__PRINT_TAB: + ld hl, __PRINT_TAB1 + jp __PRINT_SET_STATE + +__PRINT_TAB1: + ld (MEM0), a + ld hl, __PRINT_TAB2 + ld (PRINT_JUMP_STATE), hl + ret + +__PRINT_TAB2: + ld a, (MEM0) ; Load tab code (ignore the current one) + push hl + push de + push bc + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl + call PRINT_TAB + pop bc + pop de + pop hl + ret + +__PRINT_NOP: +__PRINT_RESTART: + ld hl, __PRINT_START + jp __PRINT_SET_STATE + +__PRINT_AT: + ld hl, __PRINT_AT1 + +__PRINT_SET_STATE: + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + exx + ret + +__PRINT_AT1: ; Jumps here if waiting for 1st parameter + exx + ld hl, __PRINT_AT2 + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + jp __PRINT_AT1_END + +__PRINT_AT2: + exx + ld hl, __PRINT_START + ld (PRINT_JUMP_STATE), hl ; Saves next entry call + call __LOAD_S_POSN + ld e, a + ld hl, (MAXX) + cp (hl) + jr c, __PRINT_AT2_END + jr __PRINT_EOL1 + +__PRINT_DEL: + call __LOAD_S_POSN ; Gets current screen position + dec e + ld a, -1 + cp e + jp nz, __PRINT_AT2_END + ld hl, (MAXX) + ld e, l + dec e + dec e + dec d + cp d + jp nz, __PRINT_AT2_END + ld d, h + dec d + jp __PRINT_AT2_END + +__PRINT_INK: + ld hl, __PRINT_INK2 + jp __PRINT_SET_STATE + +__PRINT_INK2: + exx + call INK_TMP + jp __PRINT_RESTART + +__PRINT_PAP: + ld hl, __PRINT_PAP2 + jp __PRINT_SET_STATE + +__PRINT_PAP2: + exx + call PAPER_TMP + jp __PRINT_RESTART + +__PRINT_FLA: + ld hl, __PRINT_FLA2 + jp __PRINT_SET_STATE + +__PRINT_FLA2: + exx + call FLASH_TMP + jp __PRINT_RESTART + +__PRINT_BRI: + ld hl, __PRINT_BRI2 + jp __PRINT_SET_STATE + +__PRINT_BRI2: + exx + call BRIGHT_TMP + jp __PRINT_RESTART + +__PRINT_INV: + ld hl, __PRINT_INV2 + jp __PRINT_SET_STATE + +__PRINT_INV2: + exx + call INVERSE_TMP + jp __PRINT_RESTART + +__PRINT_OVR: + ld hl, __PRINT_OVR2 + jp __PRINT_SET_STATE + +__PRINT_OVR2: + exx + call OVER_TMP + jp __PRINT_RESTART + +__PRINT_BOLD: + ld hl, __PRINT_BOLD2 + jp __PRINT_SET_STATE + +__PRINT_BOLD2: + exx + call BOLD_TMP + jp __PRINT_RESTART + +__PRINT_ITA: + ld hl, __PRINT_ITA2 + jp __PRINT_SET_STATE + +__PRINT_ITA2: + exx + call ITALIC_TMP + jp __PRINT_RESTART + + +__BOLD: + push hl + ld hl, MEM0 + ld b, 8 +__BOLD_LOOP: + ld a, (de) + ld c, a + rlca + or c + ld (hl), a + inc hl + inc de + djnz __BOLD_LOOP + pop hl + ld de, MEM0 + ret + + +__ITALIC: + push hl + ld hl, MEM0 + ex de, hl + ld bc, 8 + ldir + ld hl, MEM0 + srl (hl) + inc hl + srl (hl) + inc hl + srl (hl) + inc hl + inc hl + inc hl + sla (hl) + inc hl + sla (hl) + inc hl + sla (hl) + pop hl + ld de, MEM0 + ret + +PRINT_COMMA: + call __LOAD_S_POSN + ld a, e + and 16 + add a, 16 + +PRINT_TAB: + PROC + LOCAL LOOP, CONTINUE + + inc a + call __LOAD_S_POSN ; e = current row + ld d, a + ld a, e + cp 21h + jr nz, CONTINUE + ld e, -1 +CONTINUE: + ld a, d + inc e + sub e ; A = A - E + and 31 ; + ret z ; Already at position E + ld b, a +LOOP: + ld a, ' ' + call __PRINTCHAR + djnz LOOP + ret + ENDP + +PRINT_AT: ; CHanges cursor to ROW, COL + ; COL in A register + ; ROW in stack + + pop hl ; Ret address + ex (sp), hl ; callee H = ROW + ld l, a + ex de, hl + + call __IN_SCREEN + ret nc ; Return if out of screen + + jp __SAVE_S_POSN + + LOCAL __PRINT_COM + LOCAL __BOLD + LOCAL __BOLD_LOOP + LOCAL __ITALIC + LOCAL __PRINT_EOL1 + LOCAL __PRINT_EOL2 + LOCAL __PRINT_AT1 + LOCAL __PRINT_AT2 + LOCAL __PRINT_AT2_END + LOCAL __PRINT_BOLD + LOCAL __PRINT_BOLD2 + LOCAL __PRINT_ITA + LOCAL __PRINT_ITA2 + LOCAL __PRINT_INK + LOCAL __PRINT_PAP + LOCAL __PRINT_SET_STATE + LOCAL __PRINT_TABLE + LOCAL __PRINT_TAB, __PRINT_TAB1, __PRINT_TAB2 + +__PRINT_TABLE: ; Jump table for 0 .. 22 codes + + DW __PRINT_NOP ; 0 + DW __PRINT_NOP ; 1 + DW __PRINT_NOP ; 2 + DW __PRINT_NOP ; 3 + DW __PRINT_NOP ; 4 + DW __PRINT_NOP ; 5 + DW __PRINT_COM ; 6 COMMA + DW __PRINT_NOP ; 7 + DW __PRINT_DEL ; 8 DEL + DW __PRINT_NOP ; 9 + DW __PRINT_NOP ; 10 + DW __PRINT_NOP ; 11 + DW __PRINT_NOP ; 12 + DW __PRINT_0Dh ; 13 + DW __PRINT_BOLD ; 14 + DW __PRINT_ITA ; 15 + DW __PRINT_INK ; 16 + DW __PRINT_PAP ; 17 + DW __PRINT_FLA ; 18 + DW __PRINT_BRI ; 19 + DW __PRINT_INV ; 20 + DW __PRINT_OVR ; 21 + DW __PRINT_AT ; 22 AT + DW __PRINT_TAB ; 23 TAB + + ENDP + + +#line 39 "print_arrstr.bas" +#line 1 "printstr.asm" + + + + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 5 "printstr.asm" + + ; PRINT command routine + ; Prints string pointed by HL + +PRINT_STR: +__PRINTSTR: ; __FASTCALL__ Entry to print_string + PROC + LOCAL __PRINT_STR_LOOP + LOCAL __PRINT_STR_END + + ld d, a ; Saves A reg (Flag) for later + + ld a, h + or l + ret z ; Return if the pointer is NULL + + push hl + + ld c, (hl) + inc hl + ld b, (hl) + inc hl ; BC = LEN(a$); HL = &a$ + +__PRINT_STR_LOOP: + ld a, b + or c + jr z, __PRINT_STR_END ; END if BC (counter = 0) + + ld a, (hl) + call __PRINTCHAR + inc hl + dec bc + jp __PRINT_STR_LOOP + +__PRINT_STR_END: + pop hl + ld a, d ; Recovers A flag + or a ; If not 0 this is a temporary string. Free it + ret z + jp __MEM_FREE ; Frees str from heap and return from there + +__PRINT_STR: + ; Fastcall Entry + ; It ONLY prints strings + ; HL = String start + ; BC = String length (Number of chars) + push hl ; Push str address for later + ld d, a ; Saves a FLAG + jp __PRINT_STR_LOOP + + ENDP + +#line 40 "print_arrstr.bas" +#line 1 "storestr.asm" + +; vim:ts=4:et:sw=4 + ; Stores value of current string pointed by DE register into address pointed by HL + ; Returns DE = Address pointer (&a$) + ; Returns HL = HL (b$ => might be needed later to free it from the heap) + ; + ; e.g. => HL = _variableName (DIM _variableName$) + ; DE = Address into the HEAP + ; + ; This function will resize (REALLOC) the space pointed by HL + ; before copying the content of b$ into a$ + + +#line 1 "strcpy.asm" + +#line 1 "realloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + + + + ; --------------------------------------------------------------------- + ; MEM_REALLOC + ; Reallocates a block of memory in the heap. + ; + ; Parameters + ; HL = Pointer to the original block + ; BC = New Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; +; Notes: + ; If BC = 0, the block is freed, otherwise + ; the content of the original block is copied to the new one, and + ; the new size is adjusted. If BC < original length, the content + ; will be truncated. Otherwise, extra block content might contain + ; memory garbage. + ; + ; --------------------------------------------------------------------- +__REALLOC: ; Reallocates block pointed by HL, with new length BC + PROC + + LOCAL __REALLOC_END + + ld a, h + or l + jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc + + ld e, (hl) + inc hl + ld d, (hl) ; DE = First 2 bytes of HL block + + push hl + exx + pop de + inc de ; DE' <- HL + 2 + exx ; DE' <- HL (Saves current pointer into DE') + + dec hl ; HL = Block start + + push de + push bc + call __MEM_FREE ; Frees current block + pop bc + push bc + call __MEM_ALLOC ; Gets a new block of length BC + pop bc + pop de + + ld a, h + or l + ret z ; Return if HL == NULL (No memory) + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Recovers first 2 bytes in HL + + dec bc + dec bc ; BC = BC - 2 (Two bytes copied) + + ld a, b + or c + jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) + + exx + push de + exx + pop de ; DE <- DE' ; Start of remaining block + + push hl ; Saves current Block + 2 start + ex de, hl ; Exchanges them: DE is destiny block + ldir ; Copies BC Bytes + pop hl ; Recovers Block + 2 start + +__REALLOC_END: + + dec hl ; Set HL + dec hl ; To begin of block + ret + + ENDP + +#line 2 "strcpy.asm" + + ; String library + + +__STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) + PROC + + LOCAL __STRREALLOC + LOCAL __STRCONTINUE + LOCAL __B_IS_NULL + LOCAL __NOTHING_TO_COPY + + ld b, d + ld c, e + ld a, b + or c + jr z, __B_IS_NULL + + ex de, hl + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(b$) + ex de, hl ; DE = &b$ + +__B_IS_NULL: ; Jumps here if B$ pointer is NULL + inc bc + inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) + + push de + push hl + + ld a, h + or l + jr z, __STRREALLOC + + dec hl + ld d, (hl) + dec hl + ld e, (hl) ; DE = MEMBLOCKSIZE(a$) + dec de + dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) + + ld h, b + ld l, c ; HL = LEN(b$) + 2 => Minimum block size required + ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 + + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) + sbc hl, de ; Carry if len(b$) > Blocklen(a$) + jr c, __STRREALLOC ; No need to realloc + ; Need to reallocate at least to len(b$) + 2 + ex de, hl ; DE = Remaining bytes in a$ mem block. + ld hl, 4 + sbc hl, de ; if remaining bytes < 4 we can continue + jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes + +__STRREALLOC: + pop hl + call __REALLOC ; Returns in HL a new pointer with BC bytes allocated + push hl + +__STRCONTINUE: ; Pops hl and de SWAPPED + pop de ; DE = &a$ + pop hl ; HL = &b$ + + ld a, d ; Return if not enough memory for new length + or e + ret z ; Return if DE == NULL (0) + +__STRCPY: ; Copies string pointed by HL into string pointed by DE + ; Returns DE as HL (new pointer) + ld a, h + or l + jr z, __NOTHING_TO_COPY + ld c, (hl) + inc hl + ld b, (hl) + dec hl + inc bc + inc bc + push de + ldir + pop hl + ret + +__NOTHING_TO_COPY: + ex de, hl + ld (hl), e + inc hl + ld (hl), d + dec hl + ret + + ENDP + +#line 14 "storestr.asm" + +__PISTORE_STR: ; Indirect assignement at (IX + BC) + push ix + pop hl + add hl, bc + +__ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + +__STORE_STR: + push de ; Pointer to b$ + push hl ; Array pointer to variable memory address + + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation + ex de, hl ; DE = new address of a$ + pop hl ; Recover variable memory address pointer + + ld (hl), e + inc hl + ld (hl), d ; Stores a$ ptr into elemem ptr + + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) + ret + +#line 41 "print_arrstr.bas" + +ZXBASIC_USER_DATA: +_a: + DEFW 0000h + DEFB 02h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/print_arrstr.bas b/tests/functional/print_arrstr.bas new file mode 100644 index 000000000..233c4a498 --- /dev/null +++ b/tests/functional/print_arrstr.bas @@ -0,0 +1,5 @@ +DIM a$(10) +LET a$(5) = "HELLO WORLD" +PRINT a$(5) + + From 18e70d617be5c34aff7e6bf5b69a5ac6d174c5b4 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 7 Apr 2018 11:55:22 +0200 Subject: [PATCH 200/247] bugfix: bad -O2 optimization --- arch/zx48k/backend/__init__.py | 2 + tests/functional/opt2_snake_es.asm | 385 +++++++++++++++++++++++++++++ tests/functional/opt2_snake_es.bas | 6 + 3 files changed, 393 insertions(+) create mode 100644 tests/functional/opt2_snake_es.asm create mode 100644 tests/functional/opt2_snake_es.bas diff --git a/arch/zx48k/backend/__init__.py b/arch/zx48k/backend/__init__.py index 02e60806f..cbf1fb983 100644 --- a/arch/zx48k/backend/__init__.py +++ b/arch/zx48k/backend/__init__.py @@ -2619,6 +2619,8 @@ def output_join(output, new_chunk): and i0 == 'ld' and o0[0] == 'a' and len(output) > 2: ii = inst(output[-3]) oo = oper(output[-3]) + if i1 in ('add', 'adc', 'sbc'): + i1 = i1 + ' a,' if ii == 'ld' and oo[0] == 'h' and oo[1] != 'a': output[-1] = '{0} {1}'.format(i1, oo[1]) output.pop(-3) diff --git a/tests/functional/opt2_snake_es.asm b/tests/functional/opt2_snake_es.asm new file mode 100644 index 000000000..5540c63da --- /dev/null +++ b/tests/functional/opt2_snake_es.asm @@ -0,0 +1,385 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld a, (_cx) + add a, 2 + ld l, a + ld h, 0 + push hl + ld a, (_cy) + add a, 2 + ld l, a + ld h, 0 + push hl + ld hl, _y + call __ARRAY + ld a, (_cy) + add a, (hl) + ld (_ny), a + ld (0), a + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + pop iy + pop ix + exx + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "array.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; ------------------------------------------------------------------- + ; Simple array Index routine + ; Number of total indexes dimensions - 1 at beginning of memory + ; HL = Start of array memory (First two bytes contains N-1 dimensions) + ; Dimension values on the stack, (top of the stack, highest dimension) + ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> + + ; For any array of N dimension A(aN-1, ..., a1, a0) + ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as + ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] +; What I will do here is to calculate the following sequence: + ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... + + +#line 1 "mul16.asm" + +__MUL16: ; Mutiplies HL with the last value stored into de stack + ; Works for both signed and unsigned + + PROC + + LOCAL __MUL16LOOP + LOCAL __MUL16NOADD + + ex de, hl + pop hl ; Return address + ex (sp), hl ; CALLEE caller convention + +;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand + ;; ld c, h + ;; ld a, l ; C,A => 1st Operand + ;; + ;; ld hl, 0 ; Accumulator + ;; ld b, 16 + ;; +;;__MUL16LOOP: + ;; sra c ; C,A >> 1 (Arithmetic) + ;; rra + ;; + ;; jr nc, __MUL16NOADD + ;; add hl, de + ;; +;;__MUL16NOADD: + ;; sla e + ;; rl d + ;; + ;; djnz __MUL16LOOP + +__MUL16_FAST: + ld b, 16 + ld a, d + ld c, e + ex de, hl + ld hl, 0 + +__MUL16LOOP: + add hl, hl ; hl << 1 + sla c + rla ; a,c << 1 + jp nc, __MUL16NOADD + add hl, de + +__MUL16NOADD: + djnz __MUL16LOOP + + ret ; Result in hl (16 lower bits) + + ENDP + +#line 20 "array.asm" + +#line 24 "/src/zxb/trunk/library-asm/array.asm" + +__ARRAY: + PROC + + LOCAL LOOP + LOCAL ARRAY_END + LOCAL RET_ADDRESS ; Stores return address + + ex (sp), hl ; Return address in HL, array address in the stack + ld (RET_ADDRESS + 1), hl ; Stores it for later + + exx + pop hl ; Will use H'L' as the pointer + ld c, (hl) ; Loads Number of dimensions from (hl) + inc hl + ld b, (hl) + inc hl ; Ready + exx + + ld hl, 0 ; BC = Offset "accumulator" + +#line 48 "/src/zxb/trunk/library-asm/array.asm" + +LOOP: + pop bc ; Get next index (Ai) from the stack + +#line 60 "/src/zxb/trunk/library-asm/array.asm" + + add hl, bc ; Adds current index + + exx ; Checks if B'C' = 0 + ld a, b ; Which means we must exit (last element is not multiplied by anything) + or c + jr z, ARRAY_END ; if B'Ci == 0 we are done + + ld e, (hl) ; Loads next dimension into D'E' + inc hl + ld d, (hl) + inc hl + push de + dec bc ; Decrements loop counter + exx + pop de ; DE = Max bound Number (i-th dimension) + +#line 80 "/src/zxb/trunk/library-asm/array.asm" + ;call __MUL16_FAST ; HL *= DE + call __FNMUL +#line 86 "/src/zxb/trunk/library-asm/array.asm" + jp LOOP + +ARRAY_END: + ld e, (hl) + inc hl + ld d, c ; C = 0 => DE = E = Element size + push hl + push de + exx + +#line 100 "/src/zxb/trunk/library-asm/array.asm" + LOCAL ARRAY_SIZE_LOOP + + ex de, hl + ld hl, 0 + pop bc + ld b, c +ARRAY_SIZE_LOOP: + add hl, de + djnz ARRAY_SIZE_LOOP + + ;; Even faster + ;pop bc + + ;ld d, h + ;ld e, l + + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, hl + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, hl + ;dec c + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, de + ;__ARRAY_FIN: +#line 131 "/src/zxb/trunk/library-asm/array.asm" + + pop de + add hl, de ; Adds element start + +RET_ADDRESS: + ld de, 0 + push de + ret ; HL = (Start of Elements + Offset) + + ;; Performs a faster multiply for little 16bit numbs + LOCAL __FNMUL, __FNMUL2 + +__FNMUL: + xor a + or d + jp nz, __MUL16_FAST + + or e + ex de, hl + ret z + + cp 33 + jp nc, __MUL16_FAST + + ld b, l + ld l, h ; HL = 0 + +__FNMUL2: + add hl, de + djnz __FNMUL2 + ret + + ENDP + +#line 34 "opt2_snake_es.bas" + +ZXBASIC_USER_DATA: +_ny: + DEFB 00 +_cx: + DEFB 00 +_cy: + DEFB 00 +_y: + DEFW 0001h + DEFW 000Bh + DEFB 01h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/opt2_snake_es.bas b/tests/functional/opt2_snake_es.bas new file mode 100644 index 000000000..3ef583714 --- /dev/null +++ b/tests/functional/opt2_snake_es.bas @@ -0,0 +1,6 @@ +DIM y(10, 10) as UByte +DIM ny, cx, cy as UByte + +LET ny = cy + y(cy+2,cx+2) +POKE 0, ny + From 2a17fb68e1d3fb75bb68a6bc0af1c2965d3770c8 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 8 Apr 2018 13:42:50 +0200 Subject: [PATCH 201/247] pytest_cache/ ignored --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 83c4055a5..faa4ff652 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.egg-info/ *.pyc .cache/ +.pytest_cache/ .idea/ .python-version .tox/ From 3178345e3fa88fd2ae89cab1428cdb5f12130913 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 7 Apr 2018 13:00:49 +0200 Subject: [PATCH 202/247] bugfix: syntax for func definition need separator FUNCTION f() END FUNCTION was allowed. Now it's not. A color or new line is required before "END" token. --- tests/functional/def_func_inline.bas | 3 ++ tests/functional/def_func_inline_ok.asm | 43 +++++++++++++++++++++++++ tests/functional/def_func_inline_ok.bas | 3 ++ tests/functional/test_errmsg.txt | 2 ++ zxbparser.py | 11 +++++-- 5 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 tests/functional/def_func_inline.bas create mode 100644 tests/functional/def_func_inline_ok.asm create mode 100644 tests/functional/def_func_inline_ok.bas diff --git a/tests/functional/def_func_inline.bas b/tests/functional/def_func_inline.bas new file mode 100644 index 000000000..f5d6fa0c2 --- /dev/null +++ b/tests/functional/def_func_inline.bas @@ -0,0 +1,3 @@ + +FUNCTION f() END FUNCTION + diff --git a/tests/functional/def_func_inline_ok.asm b/tests/functional/def_func_inline_ok.asm new file mode 100644 index 000000000..c6df31a38 --- /dev/null +++ b/tests/functional/def_func_inline_ok.asm @@ -0,0 +1,43 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +_f: + push ix + ld ix, 0 + add ix, sp +_f__leave: + ld sp, ix + pop ix + ret + +ZXBASIC_USER_DATA: + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/def_func_inline_ok.bas b/tests/functional/def_func_inline_ok.bas new file mode 100644 index 000000000..d711fd3d6 --- /dev/null +++ b/tests/functional/def_func_inline_ok.bas @@ -0,0 +1,3 @@ + +FUNCTION f(): END FUNCTION + diff --git a/tests/functional/test_errmsg.txt b/tests/functional/test_errmsg.txt index 7f83c2115..9af4012b8 100644 --- a/tests/functional/test_errmsg.txt +++ b/tests/functional/test_errmsg.txt @@ -119,4 +119,6 @@ llb.bas:3: Undeclared function "f$" substr_expr_err.bas:3: Expected a string type expression. Got byte type instead >>> process_file('dup_func_decl.bas') dup_func_decl.bas:5: duplicated declaration for function 'f' +>>> process_file('def_func_inline.bas') +def_func_inline.bas:2: Syntax Error. Unexpected token 'END' diff --git a/zxbparser.py b/zxbparser.py index 9dbaf966e..eb3aaebc0 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -2625,7 +2625,7 @@ def p_funcdecl(p): def p_funcdeclforward(p): - """ function_declaration : DECLARE function_header + """ function_declaration : DECLARE function_header_pre """ if p[2] is None: if FUNCTION_LEVEL: @@ -2641,7 +2641,14 @@ def p_funcdeclforward(p): def p_function_header(p): - """ function_header : function_def param_decl typedef + """ function_header : function_header_pre CO + | function_header_pre NEWLINE + """ + p[0] = p[1] + + +def p_function_header_pre(p): + """ function_header_pre : function_def param_decl typedef """ if p[1] is None or p[2] is None: p[0] = None From 4af4a06b89b8eb0ee644e8ff30d1f1a4594a02a7 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 7 Apr 2018 19:34:27 +0200 Subject: [PATCH 203/247] bugfix: syntax for function def inline FUNCTION f(): PRINT: END FUNCTION (for example) is now allowed. --- tests/functional/def_func_inline_for_next.asm | 59 +++++++++++++++++++ tests/functional/def_func_inline_for_next.bas | 3 + zxbparser.py | 2 + 3 files changed, 64 insertions(+) create mode 100644 tests/functional/def_func_inline_for_next.asm create mode 100644 tests/functional/def_func_inline_for_next.bas diff --git a/tests/functional/def_func_inline_for_next.asm b/tests/functional/def_func_inline_for_next.asm new file mode 100644 index 000000000..5d2c75363 --- /dev/null +++ b/tests/functional/def_func_inline_for_next.asm @@ -0,0 +1,59 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +_f: + push ix + ld ix, 0 + add ix, sp + ld hl, 0 + push hl + inc sp + ld (ix-1), 1 + jp __LABEL0 +__LABEL3: +__LABEL4: + inc (ix-1) +__LABEL0: + ld a, (ix-1) + push af + ld a, 5 + pop hl + cp h + jp nc, __LABEL3 +__LABEL2: +_f__leave: + ld sp, ix + pop ix + ret + +ZXBASIC_USER_DATA: + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/def_func_inline_for_next.bas b/tests/functional/def_func_inline_for_next.bas new file mode 100644 index 000000000..c0e763cc8 --- /dev/null +++ b/tests/functional/def_func_inline_for_next.bas @@ -0,0 +1,3 @@ + +FUNCTION f(): FOR i = 1 TO 5: NEXT: END FUNCTION + diff --git a/zxbparser.py b/zxbparser.py index eb3aaebc0..8ed3aeb71 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -2807,6 +2807,8 @@ def p_param_def_type(p): def p_function_body(p): """ function_body : program_co END FUNCTION | program_co END SUB + | statements_co END FUNCTION + | statements_co END SUB | co_statements_co END FUNCTION | co_statements_co END SUB | END FUNCTION From eaf611ef89b00213948221fce1f9d3f65c3a31c3 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 8 Apr 2018 11:11:22 +0200 Subject: [PATCH 204/247] feature: add support for substr assign in array The following syntax cases are now supported: * LET a$(3)(2 TO 5) = "Expression" * LET a$(5, 3 TO) = "Expression" * LET a$(5, TO 3) = "Expression" * LET a$(3, TO) = "Expression" * LET a$(5, 3 TO 5) = "Expression" * LET aR(5, 3) = "Expression" also fix a crash on wrong array dims This program (for example) crashed the compiler: DIM a(10) LET a(1, 2) = 5 Instead of just showing a syntax error --- arch/zx48k/translator.py | 45 + tests/functional/let_array_substr.asm | 1371 +++++++++++++++++++++ tests/functional/let_array_substr.bas | 5 + tests/functional/let_array_substr1.asm | 1371 +++++++++++++++++++++ tests/functional/let_array_substr1.bas | 5 + tests/functional/let_array_substr10.asm | 1155 +++++++++++++++++ tests/functional/let_array_substr10.bas | 4 + tests/functional/let_array_substr11.asm | 1155 +++++++++++++++++ tests/functional/let_array_substr11.bas | 4 + tests/functional/let_array_substr12.asm | 1155 +++++++++++++++++ tests/functional/let_array_substr12.bas | 4 + tests/functional/let_array_substr13.asm | 1155 +++++++++++++++++ tests/functional/let_array_substr13.bas | 4 + tests/functional/let_array_substr2.asm | 1155 +++++++++++++++++ tests/functional/let_array_substr2.bas | 4 + tests/functional/let_array_substr3.asm | 1155 +++++++++++++++++ tests/functional/let_array_substr3.bas | 4 + tests/functional/let_array_substr4.bas | 3 + tests/functional/let_array_substr5.asm | 1371 +++++++++++++++++++++ tests/functional/let_array_substr5.bas | 5 + tests/functional/let_array_substr6.bas | 3 + tests/functional/let_array_substr7.asm | 1155 +++++++++++++++++ tests/functional/let_array_substr7.bas | 4 + tests/functional/let_array_substr8.bas | 5 + tests/functional/let_array_substr9.asm | 1155 +++++++++++++++++ tests/functional/let_array_substr9.bas | 4 + tests/functional/let_array_wrong_dims.bas | 3 + tests/functional/test_errmsg.txt | 8 + zxbparser.py | 144 ++- 29 files changed, 13601 insertions(+), 10 deletions(-) create mode 100644 tests/functional/let_array_substr.asm create mode 100644 tests/functional/let_array_substr.bas create mode 100644 tests/functional/let_array_substr1.asm create mode 100644 tests/functional/let_array_substr1.bas create mode 100644 tests/functional/let_array_substr10.asm create mode 100644 tests/functional/let_array_substr10.bas create mode 100644 tests/functional/let_array_substr11.asm create mode 100644 tests/functional/let_array_substr11.bas create mode 100644 tests/functional/let_array_substr12.asm create mode 100644 tests/functional/let_array_substr12.bas create mode 100644 tests/functional/let_array_substr13.asm create mode 100644 tests/functional/let_array_substr13.bas create mode 100644 tests/functional/let_array_substr2.asm create mode 100644 tests/functional/let_array_substr2.bas create mode 100644 tests/functional/let_array_substr3.asm create mode 100644 tests/functional/let_array_substr3.bas create mode 100644 tests/functional/let_array_substr4.bas create mode 100644 tests/functional/let_array_substr5.asm create mode 100644 tests/functional/let_array_substr5.bas create mode 100644 tests/functional/let_array_substr6.bas create mode 100644 tests/functional/let_array_substr7.asm create mode 100644 tests/functional/let_array_substr7.bas create mode 100644 tests/functional/let_array_substr8.bas create mode 100644 tests/functional/let_array_substr9.asm create mode 100644 tests/functional/let_array_substr9.bas create mode 100644 tests/functional/let_array_wrong_dims.bas diff --git a/arch/zx48k/translator.py b/arch/zx48k/translator.py index 923cea7aa..48cccfaa6 100644 --- a/arch/zx48k/translator.py +++ b/arch/zx48k/translator.py @@ -596,6 +596,51 @@ def visit_LETSUBSTR(self, node): self.emit('call', '__LETSUBSTR', 0) backend.REQUIRES.add('letsubstr.asm') + def visit_LETARRAYSUBSTR(self, node): + if self.O_LEVEL > 1 and not node.children[0].entry.accessed: + return + + expr = node.children[3] # right expression + yield expr + self.emit('paramstr', expr.t) + + if expr.token != 'STRING' and (expr.token != 'VAR' or expr.mangled[0] != '_'): + self.emit('paramu8', 1) # If the argument is not a variable, it must be freed + else: + self.emit('paramu8', 0) + + yield node.children[1] + self.emit('param' + self.TSUFFIX(gl.PTR_TYPE), node.children[1].t) + yield node.children[2] + self.emit('param' + self.TSUFFIX(gl.PTR_TYPE), node.children[2].t) + + node_ = node.children[0] + scope = node_.scope + entry = node_.entry + suffix = self.TSUFFIX(gl.PTR_TYPE) + + # Address of an array element. + if node_.offset is None: + yield node_ + if scope == SCOPE.global_: + self.emit('aload' + suffix, node_.t, entry.mangled) + elif scope == 'parameter': + self.emit('paloadstr' + suffix, node_.t, entry.offset) + elif scope == 'local': + self.emit('paloadstr' + suffix, node_.t, -entry.offset) + else: + offset = node_.offset + if scope == SCOPE.global_: + self.emit('load' + suffix, entry.t, '%s + %i' % (entry.mangled, offset)) + elif scope == SCOPE.parameter: + self.emit('pload' + suffix, node_.t, entry.offset - offset) + elif scope == SCOPE.local: + self.emit('pload' + suffix, node_.t, -(entry.offset - offset)) + + self.emit('fparam' + suffix, node.children[0].t) + self.emit('call', '__LETSUBSTR', 0) + backend.REQUIRES.add('letsubstr.asm') + def visit_ARRAYACCESS(self, node): yield node.arglist diff --git a/tests/functional/let_array_substr.asm b/tests/functional/let_array_substr.asm new file mode 100644 index 000000000..9e1d270c3 --- /dev/null +++ b/tests/functional/let_array_substr.asm @@ -0,0 +1,1371 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld hl, (_b) + push hl + ld hl, _a + call __ARRAY + ld de, __LABEL0 + call __STORE_STR + ld hl, __LABEL1 + call __LOADSTR + push hl + xor a + push af + ld hl, 1 + push hl + ld hl, 5 + push hl + ld hl, (_b) + push hl + ld hl, _a + call __ARRAY + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + call __LETSUBSTR + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__LABEL0: + DEFW 000Ah + DEFB 30h + DEFB 31h + DEFB 32h + DEFB 33h + DEFB 34h + DEFB 35h + DEFB 36h + DEFB 37h + DEFB 38h + DEFB 39h +__LABEL1: + DEFW 0005h + DEFB 48h + DEFB 45h + DEFB 4Ch + DEFB 4Ch + DEFB 4Fh +#line 1 "array.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; ------------------------------------------------------------------- + ; Simple array Index routine + ; Number of total indexes dimensions - 1 at beginning of memory + ; HL = Start of array memory (First two bytes contains N-1 dimensions) + ; Dimension values on the stack, (top of the stack, highest dimension) + ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> + + ; For any array of N dimension A(aN-1, ..., a1, a0) + ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as + ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] +; What I will do here is to calculate the following sequence: + ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... + + +#line 1 "mul16.asm" + +__MUL16: ; Mutiplies HL with the last value stored into de stack + ; Works for both signed and unsigned + + PROC + + LOCAL __MUL16LOOP + LOCAL __MUL16NOADD + + ex de, hl + pop hl ; Return address + ex (sp), hl ; CALLEE caller convention + +;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand + ;; ld c, h + ;; ld a, l ; C,A => 1st Operand + ;; + ;; ld hl, 0 ; Accumulator + ;; ld b, 16 + ;; +;;__MUL16LOOP: + ;; sra c ; C,A >> 1 (Arithmetic) + ;; rra + ;; + ;; jr nc, __MUL16NOADD + ;; add hl, de + ;; +;;__MUL16NOADD: + ;; sla e + ;; rl d + ;; + ;; djnz __MUL16LOOP + +__MUL16_FAST: + ld b, 16 + ld a, d + ld c, e + ex de, hl + ld hl, 0 + +__MUL16LOOP: + add hl, hl ; hl << 1 + sla c + rla ; a,c << 1 + jp nc, __MUL16NOADD + add hl, de + +__MUL16NOADD: + djnz __MUL16LOOP + + ret ; Result in hl (16 lower bits) + + ENDP + +#line 20 "array.asm" + +#line 24 "/src/zxb/trunk/library-asm/array.asm" + +__ARRAY: + PROC + + LOCAL LOOP + LOCAL ARRAY_END + LOCAL RET_ADDRESS ; Stores return address + + ex (sp), hl ; Return address in HL, array address in the stack + ld (RET_ADDRESS + 1), hl ; Stores it for later + + exx + pop hl ; Will use H'L' as the pointer + ld c, (hl) ; Loads Number of dimensions from (hl) + inc hl + ld b, (hl) + inc hl ; Ready + exx + + ld hl, 0 ; BC = Offset "accumulator" + +#line 48 "/src/zxb/trunk/library-asm/array.asm" + +LOOP: + pop bc ; Get next index (Ai) from the stack + +#line 60 "/src/zxb/trunk/library-asm/array.asm" + + add hl, bc ; Adds current index + + exx ; Checks if B'C' = 0 + ld a, b ; Which means we must exit (last element is not multiplied by anything) + or c + jr z, ARRAY_END ; if B'Ci == 0 we are done + + ld e, (hl) ; Loads next dimension into D'E' + inc hl + ld d, (hl) + inc hl + push de + dec bc ; Decrements loop counter + exx + pop de ; DE = Max bound Number (i-th dimension) + +#line 80 "/src/zxb/trunk/library-asm/array.asm" + ;call __MUL16_FAST ; HL *= DE + call __FNMUL +#line 86 "/src/zxb/trunk/library-asm/array.asm" + jp LOOP + +ARRAY_END: + ld e, (hl) + inc hl + ld d, c ; C = 0 => DE = E = Element size + push hl + push de + exx + +#line 100 "/src/zxb/trunk/library-asm/array.asm" + LOCAL ARRAY_SIZE_LOOP + + ex de, hl + ld hl, 0 + pop bc + ld b, c +ARRAY_SIZE_LOOP: + add hl, de + djnz ARRAY_SIZE_LOOP + + ;; Even faster + ;pop bc + + ;ld d, h + ;ld e, l + + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, hl + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, hl + ;dec c + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, de + ;__ARRAY_FIN: +#line 131 "/src/zxb/trunk/library-asm/array.asm" + + pop de + add hl, de ; Adds element start + +RET_ADDRESS: + ld de, 0 + push de + ret ; HL = (Start of Elements + Offset) + + ;; Performs a faster multiply for little 16bit numbs + LOCAL __FNMUL, __FNMUL2 + +__FNMUL: + xor a + or d + jp nz, __MUL16_FAST + + or e + ex de, hl + ret z + + cp 33 + jp nc, __MUL16_FAST + + ld b, l + ld l, h ; HL = 0 + +__FNMUL2: + add hl, de + djnz __FNMUL2 + ret + + ENDP + +#line 61 "let_array_substr.bas" +#line 1 "letsubstr.asm" + + ; Substring assigment eg. LET a$(p0 TO p1) = "xxxx" + ; HL = Start of string + ; TOP of the stack -> p1 (16 bit, unsigned) + ; TOP -1 of the stack -> p0 register + ; TOP -2 Flag (popped out in A register) + ; A Register => 0 if HL is not freed from memory + ; => Not 0 if HL must be freed from memory on exit + ; TOP -3 B$ address + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 11 "letsubstr.asm" + +__LETSUBSTR: + PROC + + LOCAL __CONT0 + LOCAL __CONT1 + LOCAL __CONT2 + LOCAL __FREE_STR + LOCAL __FREE_STR0 + + exx + pop hl ; Return address + pop de ; p1 + pop bc ; p0 + exx + + pop af ; Flag + ex af, af' ; Save it for later + + pop de ; B$ + + exx + push hl ; push ret addr back + exx + + ld a, h + or l + jp z, __FREE_STR0 ; Return if null + + ld c, (hl) + inc hl + ld b, (hl) ; BC = Str length + inc hl ; HL = String start + push bc + + exx + ex de, hl + or a + sbc hl, bc ; HL = Length of string requester by user + inc hl ; len (a$(p0 TO p1)) = p1 - p0 + 1 + ex de, hl ; Saves it in DE + + pop hl ; HL = String length + exx + jp c, __FREE_STR0 ; Return if greather + exx ; Return if p0 > p1 + + or a + sbc hl, bc ; P0 >= String length? + exx + + jp z, __FREE_STR0 ; Return if equal + jp c, __FREE_STR0 ; Return if greather + + exx + add hl, bc ; Add it back + + sbc hl, de ; Length of substring > string => Truncate it + add hl, de ; add it back + jr nc, __CONT0 ; Length of substring within a$ + + ld d, h + ld e, l ; Truncate length of substring to fit within the strlen + +__CONT0: ; At this point DE = Length of subtring to copy + ; BC = start of char to copy + push de + + push bc + exx + pop bc + + add hl, bc ; Start address (within a$) so copy from b$ (in DE) + + push hl + exx + pop hl ; Start address (within a$) so copy from b$ (in DE) + + ld b, d ; Length of string + ld c, e + + ld (hl), ' ' + ld d, h + ld e, l + inc de + dec bc + ld a, b + or c + jr z, __CONT2 + + ; At this point HL = DE = Start of Write zone in a$ + ; BC = Number of chars to write + + ldir + +__CONT2: + + pop bc ; Recovers Length of string to copy + exx + ex de, hl ; HL = Source, DE = Target + + ld a, h + or l + jp z, __FREE_STR ; Return if B$ is NULL + + ld c, (hl) + inc hl + ld b, (hl) + inc hl + + ld a, b + or c + jp z, __FREE_STR ; Return if len(b$) = 0 + + ; Now if len(b$) < len(char to copy), copy only len(b$) chars + + push de + push hl + push bc + exx + pop hl ; LEN (b$) + or a + sbc hl, bc + add hl, bc + jr nc, __CONT1 + + ; If len(b$) < len(to copy) + ld b, h ; BC = len(to copy) + ld c, l + +__CONT1: + pop hl + pop de + ldir ; Copy b$ into a$(x to y) + + exx + ex de, hl + +__FREE_STR0: + ex de, hl + +__FREE_STR: + ex af, af' + or a ; If not 0, free + jp nz, __MEM_FREE + ret + + ENDP + +#line 62 "let_array_substr.bas" +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 69 "alloc.asm" + + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 63 "let_array_substr.bas" +#line 1 "storestr.asm" + +; vim:ts=4:et:sw=4 + ; Stores value of current string pointed by DE register into address pointed by HL + ; Returns DE = Address pointer (&a$) + ; Returns HL = HL (b$ => might be needed later to free it from the heap) + ; + ; e.g. => HL = _variableName (DIM _variableName$) + ; DE = Address into the HEAP + ; + ; This function will resize (REALLOC) the space pointed by HL + ; before copying the content of b$ into a$ + + +#line 1 "strcpy.asm" + +#line 1 "realloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + + + + ; --------------------------------------------------------------------- + ; MEM_REALLOC + ; Reallocates a block of memory in the heap. + ; + ; Parameters + ; HL = Pointer to the original block + ; BC = New Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; +; Notes: + ; If BC = 0, the block is freed, otherwise + ; the content of the original block is copied to the new one, and + ; the new size is adjusted. If BC < original length, the content + ; will be truncated. Otherwise, extra block content might contain + ; memory garbage. + ; + ; --------------------------------------------------------------------- +__REALLOC: ; Reallocates block pointed by HL, with new length BC + PROC + + LOCAL __REALLOC_END + + ld a, h + or l + jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc + + ld e, (hl) + inc hl + ld d, (hl) ; DE = First 2 bytes of HL block + + push hl + exx + pop de + inc de ; DE' <- HL + 2 + exx ; DE' <- HL (Saves current pointer into DE') + + dec hl ; HL = Block start + + push de + push bc + call __MEM_FREE ; Frees current block + pop bc + push bc + call __MEM_ALLOC ; Gets a new block of length BC + pop bc + pop de + + ld a, h + or l + ret z ; Return if HL == NULL (No memory) + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Recovers first 2 bytes in HL + + dec bc + dec bc ; BC = BC - 2 (Two bytes copied) + + ld a, b + or c + jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) + + exx + push de + exx + pop de ; DE <- DE' ; Start of remaining block + + push hl ; Saves current Block + 2 start + ex de, hl ; Exchanges them: DE is destiny block + ldir ; Copies BC Bytes + pop hl ; Recovers Block + 2 start + +__REALLOC_END: + + dec hl ; Set HL + dec hl ; To begin of block + ret + + ENDP + +#line 2 "strcpy.asm" + + ; String library + + +__STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) + PROC + + LOCAL __STRREALLOC + LOCAL __STRCONTINUE + LOCAL __B_IS_NULL + LOCAL __NOTHING_TO_COPY + + ld b, d + ld c, e + ld a, b + or c + jr z, __B_IS_NULL + + ex de, hl + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(b$) + ex de, hl ; DE = &b$ + +__B_IS_NULL: ; Jumps here if B$ pointer is NULL + inc bc + inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) + + push de + push hl + + ld a, h + or l + jr z, __STRREALLOC + + dec hl + ld d, (hl) + dec hl + ld e, (hl) ; DE = MEMBLOCKSIZE(a$) + dec de + dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) + + ld h, b + ld l, c ; HL = LEN(b$) + 2 => Minimum block size required + ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 + + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) + sbc hl, de ; Carry if len(b$) > Blocklen(a$) + jr c, __STRREALLOC ; No need to realloc + ; Need to reallocate at least to len(b$) + 2 + ex de, hl ; DE = Remaining bytes in a$ mem block. + ld hl, 4 + sbc hl, de ; if remaining bytes < 4 we can continue + jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes + +__STRREALLOC: + pop hl + call __REALLOC ; Returns in HL a new pointer with BC bytes allocated + push hl + +__STRCONTINUE: ; Pops hl and de SWAPPED + pop de ; DE = &a$ + pop hl ; HL = &b$ + + ld a, d ; Return if not enough memory for new length + or e + ret z ; Return if DE == NULL (0) + +__STRCPY: ; Copies string pointed by HL into string pointed by DE + ; Returns DE as HL (new pointer) + ld a, h + or l + jr z, __NOTHING_TO_COPY + ld c, (hl) + inc hl + ld b, (hl) + dec hl + inc bc + inc bc + push de + ldir + pop hl + ret + +__NOTHING_TO_COPY: + ex de, hl + ld (hl), e + inc hl + ld (hl), d + dec hl + ret + + ENDP + +#line 14 "storestr.asm" + +__PISTORE_STR: ; Indirect assignement at (IX + BC) + push ix + pop hl + add hl, bc + +__ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + +__STORE_STR: + push de ; Pointer to b$ + push hl ; Array pointer to variable memory address + + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation + ex de, hl ; DE = new address of a$ + pop hl ; Recover variable memory address pointer + + ld (hl), e + inc hl + ld (hl), d ; Stores a$ ptr into elemem ptr + + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) + ret + +#line 64 "let_array_substr.bas" + +ZXBASIC_USER_DATA: +_b: + DEFB 03h + DEFB 00h +_a: + DEFW 0000h + DEFB 02h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/let_array_substr.bas b/tests/functional/let_array_substr.bas new file mode 100644 index 000000000..7258295b6 --- /dev/null +++ b/tests/functional/let_array_substr.bas @@ -0,0 +1,5 @@ +DIM a$(10) +DIM b as UInteger = 3 +LET a$(b) = "0123456789" +LET a$(b)(1 TO 5) = "HELLO" + diff --git a/tests/functional/let_array_substr1.asm b/tests/functional/let_array_substr1.asm new file mode 100644 index 000000000..eb062d890 --- /dev/null +++ b/tests/functional/let_array_substr1.asm @@ -0,0 +1,1371 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld hl, (_b) + push hl + ld hl, _a + call __ARRAY + ld de, __LABEL0 + call __STORE_STR + ld hl, __LABEL1 + call __LOADSTR + push hl + xor a + push af + ld hl, 1 + push hl + ld hl, 5 + push hl + ld hl, (_b) + push hl + ld hl, _a + call __ARRAY + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + call __LETSUBSTR + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__LABEL0: + DEFW 000Ah + DEFB 30h + DEFB 31h + DEFB 32h + DEFB 33h + DEFB 34h + DEFB 35h + DEFB 36h + DEFB 37h + DEFB 38h + DEFB 39h +__LABEL1: + DEFW 0005h + DEFB 48h + DEFB 45h + DEFB 4Ch + DEFB 4Ch + DEFB 4Fh +#line 1 "array.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; ------------------------------------------------------------------- + ; Simple array Index routine + ; Number of total indexes dimensions - 1 at beginning of memory + ; HL = Start of array memory (First two bytes contains N-1 dimensions) + ; Dimension values on the stack, (top of the stack, highest dimension) + ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> + + ; For any array of N dimension A(aN-1, ..., a1, a0) + ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as + ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] +; What I will do here is to calculate the following sequence: + ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... + + +#line 1 "mul16.asm" + +__MUL16: ; Mutiplies HL with the last value stored into de stack + ; Works for both signed and unsigned + + PROC + + LOCAL __MUL16LOOP + LOCAL __MUL16NOADD + + ex de, hl + pop hl ; Return address + ex (sp), hl ; CALLEE caller convention + +;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand + ;; ld c, h + ;; ld a, l ; C,A => 1st Operand + ;; + ;; ld hl, 0 ; Accumulator + ;; ld b, 16 + ;; +;;__MUL16LOOP: + ;; sra c ; C,A >> 1 (Arithmetic) + ;; rra + ;; + ;; jr nc, __MUL16NOADD + ;; add hl, de + ;; +;;__MUL16NOADD: + ;; sla e + ;; rl d + ;; + ;; djnz __MUL16LOOP + +__MUL16_FAST: + ld b, 16 + ld a, d + ld c, e + ex de, hl + ld hl, 0 + +__MUL16LOOP: + add hl, hl ; hl << 1 + sla c + rla ; a,c << 1 + jp nc, __MUL16NOADD + add hl, de + +__MUL16NOADD: + djnz __MUL16LOOP + + ret ; Result in hl (16 lower bits) + + ENDP + +#line 20 "array.asm" + +#line 24 "/src/zxb/trunk/library-asm/array.asm" + +__ARRAY: + PROC + + LOCAL LOOP + LOCAL ARRAY_END + LOCAL RET_ADDRESS ; Stores return address + + ex (sp), hl ; Return address in HL, array address in the stack + ld (RET_ADDRESS + 1), hl ; Stores it for later + + exx + pop hl ; Will use H'L' as the pointer + ld c, (hl) ; Loads Number of dimensions from (hl) + inc hl + ld b, (hl) + inc hl ; Ready + exx + + ld hl, 0 ; BC = Offset "accumulator" + +#line 48 "/src/zxb/trunk/library-asm/array.asm" + +LOOP: + pop bc ; Get next index (Ai) from the stack + +#line 60 "/src/zxb/trunk/library-asm/array.asm" + + add hl, bc ; Adds current index + + exx ; Checks if B'C' = 0 + ld a, b ; Which means we must exit (last element is not multiplied by anything) + or c + jr z, ARRAY_END ; if B'Ci == 0 we are done + + ld e, (hl) ; Loads next dimension into D'E' + inc hl + ld d, (hl) + inc hl + push de + dec bc ; Decrements loop counter + exx + pop de ; DE = Max bound Number (i-th dimension) + +#line 80 "/src/zxb/trunk/library-asm/array.asm" + ;call __MUL16_FAST ; HL *= DE + call __FNMUL +#line 86 "/src/zxb/trunk/library-asm/array.asm" + jp LOOP + +ARRAY_END: + ld e, (hl) + inc hl + ld d, c ; C = 0 => DE = E = Element size + push hl + push de + exx + +#line 100 "/src/zxb/trunk/library-asm/array.asm" + LOCAL ARRAY_SIZE_LOOP + + ex de, hl + ld hl, 0 + pop bc + ld b, c +ARRAY_SIZE_LOOP: + add hl, de + djnz ARRAY_SIZE_LOOP + + ;; Even faster + ;pop bc + + ;ld d, h + ;ld e, l + + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, hl + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, hl + ;dec c + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, de + ;__ARRAY_FIN: +#line 131 "/src/zxb/trunk/library-asm/array.asm" + + pop de + add hl, de ; Adds element start + +RET_ADDRESS: + ld de, 0 + push de + ret ; HL = (Start of Elements + Offset) + + ;; Performs a faster multiply for little 16bit numbs + LOCAL __FNMUL, __FNMUL2 + +__FNMUL: + xor a + or d + jp nz, __MUL16_FAST + + or e + ex de, hl + ret z + + cp 33 + jp nc, __MUL16_FAST + + ld b, l + ld l, h ; HL = 0 + +__FNMUL2: + add hl, de + djnz __FNMUL2 + ret + + ENDP + +#line 61 "let_array_substr1.bas" +#line 1 "letsubstr.asm" + + ; Substring assigment eg. LET a$(p0 TO p1) = "xxxx" + ; HL = Start of string + ; TOP of the stack -> p1 (16 bit, unsigned) + ; TOP -1 of the stack -> p0 register + ; TOP -2 Flag (popped out in A register) + ; A Register => 0 if HL is not freed from memory + ; => Not 0 if HL must be freed from memory on exit + ; TOP -3 B$ address + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 11 "letsubstr.asm" + +__LETSUBSTR: + PROC + + LOCAL __CONT0 + LOCAL __CONT1 + LOCAL __CONT2 + LOCAL __FREE_STR + LOCAL __FREE_STR0 + + exx + pop hl ; Return address + pop de ; p1 + pop bc ; p0 + exx + + pop af ; Flag + ex af, af' ; Save it for later + + pop de ; B$ + + exx + push hl ; push ret addr back + exx + + ld a, h + or l + jp z, __FREE_STR0 ; Return if null + + ld c, (hl) + inc hl + ld b, (hl) ; BC = Str length + inc hl ; HL = String start + push bc + + exx + ex de, hl + or a + sbc hl, bc ; HL = Length of string requester by user + inc hl ; len (a$(p0 TO p1)) = p1 - p0 + 1 + ex de, hl ; Saves it in DE + + pop hl ; HL = String length + exx + jp c, __FREE_STR0 ; Return if greather + exx ; Return if p0 > p1 + + or a + sbc hl, bc ; P0 >= String length? + exx + + jp z, __FREE_STR0 ; Return if equal + jp c, __FREE_STR0 ; Return if greather + + exx + add hl, bc ; Add it back + + sbc hl, de ; Length of substring > string => Truncate it + add hl, de ; add it back + jr nc, __CONT0 ; Length of substring within a$ + + ld d, h + ld e, l ; Truncate length of substring to fit within the strlen + +__CONT0: ; At this point DE = Length of subtring to copy + ; BC = start of char to copy + push de + + push bc + exx + pop bc + + add hl, bc ; Start address (within a$) so copy from b$ (in DE) + + push hl + exx + pop hl ; Start address (within a$) so copy from b$ (in DE) + + ld b, d ; Length of string + ld c, e + + ld (hl), ' ' + ld d, h + ld e, l + inc de + dec bc + ld a, b + or c + jr z, __CONT2 + + ; At this point HL = DE = Start of Write zone in a$ + ; BC = Number of chars to write + + ldir + +__CONT2: + + pop bc ; Recovers Length of string to copy + exx + ex de, hl ; HL = Source, DE = Target + + ld a, h + or l + jp z, __FREE_STR ; Return if B$ is NULL + + ld c, (hl) + inc hl + ld b, (hl) + inc hl + + ld a, b + or c + jp z, __FREE_STR ; Return if len(b$) = 0 + + ; Now if len(b$) < len(char to copy), copy only len(b$) chars + + push de + push hl + push bc + exx + pop hl ; LEN (b$) + or a + sbc hl, bc + add hl, bc + jr nc, __CONT1 + + ; If len(b$) < len(to copy) + ld b, h ; BC = len(to copy) + ld c, l + +__CONT1: + pop hl + pop de + ldir ; Copy b$ into a$(x to y) + + exx + ex de, hl + +__FREE_STR0: + ex de, hl + +__FREE_STR: + ex af, af' + or a ; If not 0, free + jp nz, __MEM_FREE + ret + + ENDP + +#line 62 "let_array_substr1.bas" +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 69 "alloc.asm" + + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 63 "let_array_substr1.bas" +#line 1 "storestr.asm" + +; vim:ts=4:et:sw=4 + ; Stores value of current string pointed by DE register into address pointed by HL + ; Returns DE = Address pointer (&a$) + ; Returns HL = HL (b$ => might be needed later to free it from the heap) + ; + ; e.g. => HL = _variableName (DIM _variableName$) + ; DE = Address into the HEAP + ; + ; This function will resize (REALLOC) the space pointed by HL + ; before copying the content of b$ into a$ + + +#line 1 "strcpy.asm" + +#line 1 "realloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + + + + ; --------------------------------------------------------------------- + ; MEM_REALLOC + ; Reallocates a block of memory in the heap. + ; + ; Parameters + ; HL = Pointer to the original block + ; BC = New Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; +; Notes: + ; If BC = 0, the block is freed, otherwise + ; the content of the original block is copied to the new one, and + ; the new size is adjusted. If BC < original length, the content + ; will be truncated. Otherwise, extra block content might contain + ; memory garbage. + ; + ; --------------------------------------------------------------------- +__REALLOC: ; Reallocates block pointed by HL, with new length BC + PROC + + LOCAL __REALLOC_END + + ld a, h + or l + jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc + + ld e, (hl) + inc hl + ld d, (hl) ; DE = First 2 bytes of HL block + + push hl + exx + pop de + inc de ; DE' <- HL + 2 + exx ; DE' <- HL (Saves current pointer into DE') + + dec hl ; HL = Block start + + push de + push bc + call __MEM_FREE ; Frees current block + pop bc + push bc + call __MEM_ALLOC ; Gets a new block of length BC + pop bc + pop de + + ld a, h + or l + ret z ; Return if HL == NULL (No memory) + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Recovers first 2 bytes in HL + + dec bc + dec bc ; BC = BC - 2 (Two bytes copied) + + ld a, b + or c + jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) + + exx + push de + exx + pop de ; DE <- DE' ; Start of remaining block + + push hl ; Saves current Block + 2 start + ex de, hl ; Exchanges them: DE is destiny block + ldir ; Copies BC Bytes + pop hl ; Recovers Block + 2 start + +__REALLOC_END: + + dec hl ; Set HL + dec hl ; To begin of block + ret + + ENDP + +#line 2 "strcpy.asm" + + ; String library + + +__STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) + PROC + + LOCAL __STRREALLOC + LOCAL __STRCONTINUE + LOCAL __B_IS_NULL + LOCAL __NOTHING_TO_COPY + + ld b, d + ld c, e + ld a, b + or c + jr z, __B_IS_NULL + + ex de, hl + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(b$) + ex de, hl ; DE = &b$ + +__B_IS_NULL: ; Jumps here if B$ pointer is NULL + inc bc + inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) + + push de + push hl + + ld a, h + or l + jr z, __STRREALLOC + + dec hl + ld d, (hl) + dec hl + ld e, (hl) ; DE = MEMBLOCKSIZE(a$) + dec de + dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) + + ld h, b + ld l, c ; HL = LEN(b$) + 2 => Minimum block size required + ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 + + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) + sbc hl, de ; Carry if len(b$) > Blocklen(a$) + jr c, __STRREALLOC ; No need to realloc + ; Need to reallocate at least to len(b$) + 2 + ex de, hl ; DE = Remaining bytes in a$ mem block. + ld hl, 4 + sbc hl, de ; if remaining bytes < 4 we can continue + jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes + +__STRREALLOC: + pop hl + call __REALLOC ; Returns in HL a new pointer with BC bytes allocated + push hl + +__STRCONTINUE: ; Pops hl and de SWAPPED + pop de ; DE = &a$ + pop hl ; HL = &b$ + + ld a, d ; Return if not enough memory for new length + or e + ret z ; Return if DE == NULL (0) + +__STRCPY: ; Copies string pointed by HL into string pointed by DE + ; Returns DE as HL (new pointer) + ld a, h + or l + jr z, __NOTHING_TO_COPY + ld c, (hl) + inc hl + ld b, (hl) + dec hl + inc bc + inc bc + push de + ldir + pop hl + ret + +__NOTHING_TO_COPY: + ex de, hl + ld (hl), e + inc hl + ld (hl), d + dec hl + ret + + ENDP + +#line 14 "storestr.asm" + +__PISTORE_STR: ; Indirect assignement at (IX + BC) + push ix + pop hl + add hl, bc + +__ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + +__STORE_STR: + push de ; Pointer to b$ + push hl ; Array pointer to variable memory address + + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation + ex de, hl ; DE = new address of a$ + pop hl ; Recover variable memory address pointer + + ld (hl), e + inc hl + ld (hl), d ; Stores a$ ptr into elemem ptr + + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) + ret + +#line 64 "let_array_substr1.bas" + +ZXBASIC_USER_DATA: +_b: + DEFB 03h + DEFB 00h +_a: + DEFW 0000h + DEFB 02h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/let_array_substr1.bas b/tests/functional/let_array_substr1.bas new file mode 100644 index 000000000..ae5f2f6e0 --- /dev/null +++ b/tests/functional/let_array_substr1.bas @@ -0,0 +1,5 @@ +DIM a$(10) +DIM b as UInteger = 3 +LET a$(b) = "0123456789" +a$(b)(1 TO 5) = "HELLO" + diff --git a/tests/functional/let_array_substr10.asm b/tests/functional/let_array_substr10.asm new file mode 100644 index 000000000..385dfdd1c --- /dev/null +++ b/tests/functional/let_array_substr10.asm @@ -0,0 +1,1155 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld de, __LABEL0 + ld hl, _a + 11 + call __STORE_STR + ld hl, __LABEL1 + call __LOADSTR + push hl + xor a + push af + ld hl, 0 + push hl + ld hl, 3 + push hl + ld hl, (_a + 11) + call __LETSUBSTR + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__LABEL0: + DEFW 000Ah + DEFB 30h + DEFB 31h + DEFB 32h + DEFB 33h + DEFB 34h + DEFB 35h + DEFB 36h + DEFB 37h + DEFB 38h + DEFB 39h +__LABEL1: + DEFW 0005h + DEFB 48h + DEFB 45h + DEFB 4Ch + DEFB 4Ch + DEFB 4Fh +#line 1 "letsubstr.asm" + + ; Substring assigment eg. LET a$(p0 TO p1) = "xxxx" + ; HL = Start of string + ; TOP of the stack -> p1 (16 bit, unsigned) + ; TOP -1 of the stack -> p0 register + ; TOP -2 Flag (popped out in A register) + ; A Register => 0 if HL is not freed from memory + ; => Not 0 if HL must be freed from memory on exit + ; TOP -3 B$ address + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 11 "letsubstr.asm" + +__LETSUBSTR: + PROC + + LOCAL __CONT0 + LOCAL __CONT1 + LOCAL __CONT2 + LOCAL __FREE_STR + LOCAL __FREE_STR0 + + exx + pop hl ; Return address + pop de ; p1 + pop bc ; p0 + exx + + pop af ; Flag + ex af, af' ; Save it for later + + pop de ; B$ + + exx + push hl ; push ret addr back + exx + + ld a, h + or l + jp z, __FREE_STR0 ; Return if null + + ld c, (hl) + inc hl + ld b, (hl) ; BC = Str length + inc hl ; HL = String start + push bc + + exx + ex de, hl + or a + sbc hl, bc ; HL = Length of string requester by user + inc hl ; len (a$(p0 TO p1)) = p1 - p0 + 1 + ex de, hl ; Saves it in DE + + pop hl ; HL = String length + exx + jp c, __FREE_STR0 ; Return if greather + exx ; Return if p0 > p1 + + or a + sbc hl, bc ; P0 >= String length? + exx + + jp z, __FREE_STR0 ; Return if equal + jp c, __FREE_STR0 ; Return if greather + + exx + add hl, bc ; Add it back + + sbc hl, de ; Length of substring > string => Truncate it + add hl, de ; add it back + jr nc, __CONT0 ; Length of substring within a$ + + ld d, h + ld e, l ; Truncate length of substring to fit within the strlen + +__CONT0: ; At this point DE = Length of subtring to copy + ; BC = start of char to copy + push de + + push bc + exx + pop bc + + add hl, bc ; Start address (within a$) so copy from b$ (in DE) + + push hl + exx + pop hl ; Start address (within a$) so copy from b$ (in DE) + + ld b, d ; Length of string + ld c, e + + ld (hl), ' ' + ld d, h + ld e, l + inc de + dec bc + ld a, b + or c + jr z, __CONT2 + + ; At this point HL = DE = Start of Write zone in a$ + ; BC = Number of chars to write + + ldir + +__CONT2: + + pop bc ; Recovers Length of string to copy + exx + ex de, hl ; HL = Source, DE = Target + + ld a, h + or l + jp z, __FREE_STR ; Return if B$ is NULL + + ld c, (hl) + inc hl + ld b, (hl) + inc hl + + ld a, b + or c + jp z, __FREE_STR ; Return if len(b$) = 0 + + ; Now if len(b$) < len(char to copy), copy only len(b$) chars + + push de + push hl + push bc + exx + pop hl ; LEN (b$) + or a + sbc hl, bc + add hl, bc + jr nc, __CONT1 + + ; If len(b$) < len(to copy) + ld b, h ; BC = len(to copy) + ld c, l + +__CONT1: + pop hl + pop de + ldir ; Copy b$ into a$(x to y) + + exx + ex de, hl + +__FREE_STR0: + ex de, hl + +__FREE_STR: + ex af, af' + or a ; If not 0, free + jp nz, __MEM_FREE + ret + + ENDP + +#line 51 "let_array_substr10.bas" +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 69 "alloc.asm" + + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 52 "let_array_substr10.bas" +#line 1 "storestr.asm" + +; vim:ts=4:et:sw=4 + ; Stores value of current string pointed by DE register into address pointed by HL + ; Returns DE = Address pointer (&a$) + ; Returns HL = HL (b$ => might be needed later to free it from the heap) + ; + ; e.g. => HL = _variableName (DIM _variableName$) + ; DE = Address into the HEAP + ; + ; This function will resize (REALLOC) the space pointed by HL + ; before copying the content of b$ into a$ + + +#line 1 "strcpy.asm" + +#line 1 "realloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + + + + ; --------------------------------------------------------------------- + ; MEM_REALLOC + ; Reallocates a block of memory in the heap. + ; + ; Parameters + ; HL = Pointer to the original block + ; BC = New Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; +; Notes: + ; If BC = 0, the block is freed, otherwise + ; the content of the original block is copied to the new one, and + ; the new size is adjusted. If BC < original length, the content + ; will be truncated. Otherwise, extra block content might contain + ; memory garbage. + ; + ; --------------------------------------------------------------------- +__REALLOC: ; Reallocates block pointed by HL, with new length BC + PROC + + LOCAL __REALLOC_END + + ld a, h + or l + jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc + + ld e, (hl) + inc hl + ld d, (hl) ; DE = First 2 bytes of HL block + + push hl + exx + pop de + inc de ; DE' <- HL + 2 + exx ; DE' <- HL (Saves current pointer into DE') + + dec hl ; HL = Block start + + push de + push bc + call __MEM_FREE ; Frees current block + pop bc + push bc + call __MEM_ALLOC ; Gets a new block of length BC + pop bc + pop de + + ld a, h + or l + ret z ; Return if HL == NULL (No memory) + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Recovers first 2 bytes in HL + + dec bc + dec bc ; BC = BC - 2 (Two bytes copied) + + ld a, b + or c + jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) + + exx + push de + exx + pop de ; DE <- DE' ; Start of remaining block + + push hl ; Saves current Block + 2 start + ex de, hl ; Exchanges them: DE is destiny block + ldir ; Copies BC Bytes + pop hl ; Recovers Block + 2 start + +__REALLOC_END: + + dec hl ; Set HL + dec hl ; To begin of block + ret + + ENDP + +#line 2 "strcpy.asm" + + ; String library + + +__STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) + PROC + + LOCAL __STRREALLOC + LOCAL __STRCONTINUE + LOCAL __B_IS_NULL + LOCAL __NOTHING_TO_COPY + + ld b, d + ld c, e + ld a, b + or c + jr z, __B_IS_NULL + + ex de, hl + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(b$) + ex de, hl ; DE = &b$ + +__B_IS_NULL: ; Jumps here if B$ pointer is NULL + inc bc + inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) + + push de + push hl + + ld a, h + or l + jr z, __STRREALLOC + + dec hl + ld d, (hl) + dec hl + ld e, (hl) ; DE = MEMBLOCKSIZE(a$) + dec de + dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) + + ld h, b + ld l, c ; HL = LEN(b$) + 2 => Minimum block size required + ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 + + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) + sbc hl, de ; Carry if len(b$) > Blocklen(a$) + jr c, __STRREALLOC ; No need to realloc + ; Need to reallocate at least to len(b$) + 2 + ex de, hl ; DE = Remaining bytes in a$ mem block. + ld hl, 4 + sbc hl, de ; if remaining bytes < 4 we can continue + jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes + +__STRREALLOC: + pop hl + call __REALLOC ; Returns in HL a new pointer with BC bytes allocated + push hl + +__STRCONTINUE: ; Pops hl and de SWAPPED + pop de ; DE = &a$ + pop hl ; HL = &b$ + + ld a, d ; Return if not enough memory for new length + or e + ret z ; Return if DE == NULL (0) + +__STRCPY: ; Copies string pointed by HL into string pointed by DE + ; Returns DE as HL (new pointer) + ld a, h + or l + jr z, __NOTHING_TO_COPY + ld c, (hl) + inc hl + ld b, (hl) + dec hl + inc bc + inc bc + push de + ldir + pop hl + ret + +__NOTHING_TO_COPY: + ex de, hl + ld (hl), e + inc hl + ld (hl), d + dec hl + ret + + ENDP + +#line 14 "storestr.asm" + +__PISTORE_STR: ; Indirect assignement at (IX + BC) + push ix + pop hl + add hl, bc + +__ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + +__STORE_STR: + push de ; Pointer to b$ + push hl ; Array pointer to variable memory address + + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation + ex de, hl ; DE = new address of a$ + pop hl ; Recover variable memory address pointer + + ld (hl), e + inc hl + ld (hl), d ; Stores a$ ptr into elemem ptr + + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) + ret + +#line 53 "let_array_substr10.bas" + +ZXBASIC_USER_DATA: +_a: + DEFW 0000h + DEFB 02h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/let_array_substr10.bas b/tests/functional/let_array_substr10.bas new file mode 100644 index 000000000..38123f081 --- /dev/null +++ b/tests/functional/let_array_substr10.bas @@ -0,0 +1,4 @@ +DIM a$(10) +LET a(4) = "0123456789" +LET a(4, TO 3) = "HELLO" + diff --git a/tests/functional/let_array_substr11.asm b/tests/functional/let_array_substr11.asm new file mode 100644 index 000000000..bff978cf8 --- /dev/null +++ b/tests/functional/let_array_substr11.asm @@ -0,0 +1,1155 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld de, __LABEL0 + ld hl, _a + 9 + call __STORE_STR + ld hl, __LABEL1 + call __LOADSTR + push hl + xor a + push af + ld hl, 0 + push hl + ld hl, 65534 + push hl + ld hl, (_a + 9) + call __LETSUBSTR + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__LABEL0: + DEFW 000Ah + DEFB 30h + DEFB 31h + DEFB 32h + DEFB 33h + DEFB 34h + DEFB 35h + DEFB 36h + DEFB 37h + DEFB 38h + DEFB 39h +__LABEL1: + DEFW 0005h + DEFB 48h + DEFB 45h + DEFB 4Ch + DEFB 4Ch + DEFB 4Fh +#line 1 "letsubstr.asm" + + ; Substring assigment eg. LET a$(p0 TO p1) = "xxxx" + ; HL = Start of string + ; TOP of the stack -> p1 (16 bit, unsigned) + ; TOP -1 of the stack -> p0 register + ; TOP -2 Flag (popped out in A register) + ; A Register => 0 if HL is not freed from memory + ; => Not 0 if HL must be freed from memory on exit + ; TOP -3 B$ address + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 11 "letsubstr.asm" + +__LETSUBSTR: + PROC + + LOCAL __CONT0 + LOCAL __CONT1 + LOCAL __CONT2 + LOCAL __FREE_STR + LOCAL __FREE_STR0 + + exx + pop hl ; Return address + pop de ; p1 + pop bc ; p0 + exx + + pop af ; Flag + ex af, af' ; Save it for later + + pop de ; B$ + + exx + push hl ; push ret addr back + exx + + ld a, h + or l + jp z, __FREE_STR0 ; Return if null + + ld c, (hl) + inc hl + ld b, (hl) ; BC = Str length + inc hl ; HL = String start + push bc + + exx + ex de, hl + or a + sbc hl, bc ; HL = Length of string requester by user + inc hl ; len (a$(p0 TO p1)) = p1 - p0 + 1 + ex de, hl ; Saves it in DE + + pop hl ; HL = String length + exx + jp c, __FREE_STR0 ; Return if greather + exx ; Return if p0 > p1 + + or a + sbc hl, bc ; P0 >= String length? + exx + + jp z, __FREE_STR0 ; Return if equal + jp c, __FREE_STR0 ; Return if greather + + exx + add hl, bc ; Add it back + + sbc hl, de ; Length of substring > string => Truncate it + add hl, de ; add it back + jr nc, __CONT0 ; Length of substring within a$ + + ld d, h + ld e, l ; Truncate length of substring to fit within the strlen + +__CONT0: ; At this point DE = Length of subtring to copy + ; BC = start of char to copy + push de + + push bc + exx + pop bc + + add hl, bc ; Start address (within a$) so copy from b$ (in DE) + + push hl + exx + pop hl ; Start address (within a$) so copy from b$ (in DE) + + ld b, d ; Length of string + ld c, e + + ld (hl), ' ' + ld d, h + ld e, l + inc de + dec bc + ld a, b + or c + jr z, __CONT2 + + ; At this point HL = DE = Start of Write zone in a$ + ; BC = Number of chars to write + + ldir + +__CONT2: + + pop bc ; Recovers Length of string to copy + exx + ex de, hl ; HL = Source, DE = Target + + ld a, h + or l + jp z, __FREE_STR ; Return if B$ is NULL + + ld c, (hl) + inc hl + ld b, (hl) + inc hl + + ld a, b + or c + jp z, __FREE_STR ; Return if len(b$) = 0 + + ; Now if len(b$) < len(char to copy), copy only len(b$) chars + + push de + push hl + push bc + exx + pop hl ; LEN (b$) + or a + sbc hl, bc + add hl, bc + jr nc, __CONT1 + + ; If len(b$) < len(to copy) + ld b, h ; BC = len(to copy) + ld c, l + +__CONT1: + pop hl + pop de + ldir ; Copy b$ into a$(x to y) + + exx + ex de, hl + +__FREE_STR0: + ex de, hl + +__FREE_STR: + ex af, af' + or a ; If not 0, free + jp nz, __MEM_FREE + ret + + ENDP + +#line 51 "let_array_substr11.bas" +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 69 "alloc.asm" + + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 52 "let_array_substr11.bas" +#line 1 "storestr.asm" + +; vim:ts=4:et:sw=4 + ; Stores value of current string pointed by DE register into address pointed by HL + ; Returns DE = Address pointer (&a$) + ; Returns HL = HL (b$ => might be needed later to free it from the heap) + ; + ; e.g. => HL = _variableName (DIM _variableName$) + ; DE = Address into the HEAP + ; + ; This function will resize (REALLOC) the space pointed by HL + ; before copying the content of b$ into a$ + + +#line 1 "strcpy.asm" + +#line 1 "realloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + + + + ; --------------------------------------------------------------------- + ; MEM_REALLOC + ; Reallocates a block of memory in the heap. + ; + ; Parameters + ; HL = Pointer to the original block + ; BC = New Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; +; Notes: + ; If BC = 0, the block is freed, otherwise + ; the content of the original block is copied to the new one, and + ; the new size is adjusted. If BC < original length, the content + ; will be truncated. Otherwise, extra block content might contain + ; memory garbage. + ; + ; --------------------------------------------------------------------- +__REALLOC: ; Reallocates block pointed by HL, with new length BC + PROC + + LOCAL __REALLOC_END + + ld a, h + or l + jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc + + ld e, (hl) + inc hl + ld d, (hl) ; DE = First 2 bytes of HL block + + push hl + exx + pop de + inc de ; DE' <- HL + 2 + exx ; DE' <- HL (Saves current pointer into DE') + + dec hl ; HL = Block start + + push de + push bc + call __MEM_FREE ; Frees current block + pop bc + push bc + call __MEM_ALLOC ; Gets a new block of length BC + pop bc + pop de + + ld a, h + or l + ret z ; Return if HL == NULL (No memory) + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Recovers first 2 bytes in HL + + dec bc + dec bc ; BC = BC - 2 (Two bytes copied) + + ld a, b + or c + jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) + + exx + push de + exx + pop de ; DE <- DE' ; Start of remaining block + + push hl ; Saves current Block + 2 start + ex de, hl ; Exchanges them: DE is destiny block + ldir ; Copies BC Bytes + pop hl ; Recovers Block + 2 start + +__REALLOC_END: + + dec hl ; Set HL + dec hl ; To begin of block + ret + + ENDP + +#line 2 "strcpy.asm" + + ; String library + + +__STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) + PROC + + LOCAL __STRREALLOC + LOCAL __STRCONTINUE + LOCAL __B_IS_NULL + LOCAL __NOTHING_TO_COPY + + ld b, d + ld c, e + ld a, b + or c + jr z, __B_IS_NULL + + ex de, hl + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(b$) + ex de, hl ; DE = &b$ + +__B_IS_NULL: ; Jumps here if B$ pointer is NULL + inc bc + inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) + + push de + push hl + + ld a, h + or l + jr z, __STRREALLOC + + dec hl + ld d, (hl) + dec hl + ld e, (hl) ; DE = MEMBLOCKSIZE(a$) + dec de + dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) + + ld h, b + ld l, c ; HL = LEN(b$) + 2 => Minimum block size required + ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 + + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) + sbc hl, de ; Carry if len(b$) > Blocklen(a$) + jr c, __STRREALLOC ; No need to realloc + ; Need to reallocate at least to len(b$) + 2 + ex de, hl ; DE = Remaining bytes in a$ mem block. + ld hl, 4 + sbc hl, de ; if remaining bytes < 4 we can continue + jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes + +__STRREALLOC: + pop hl + call __REALLOC ; Returns in HL a new pointer with BC bytes allocated + push hl + +__STRCONTINUE: ; Pops hl and de SWAPPED + pop de ; DE = &a$ + pop hl ; HL = &b$ + + ld a, d ; Return if not enough memory for new length + or e + ret z ; Return if DE == NULL (0) + +__STRCPY: ; Copies string pointed by HL into string pointed by DE + ; Returns DE as HL (new pointer) + ld a, h + or l + jr z, __NOTHING_TO_COPY + ld c, (hl) + inc hl + ld b, (hl) + dec hl + inc bc + inc bc + push de + ldir + pop hl + ret + +__NOTHING_TO_COPY: + ex de, hl + ld (hl), e + inc hl + ld (hl), d + dec hl + ret + + ENDP + +#line 14 "storestr.asm" + +__PISTORE_STR: ; Indirect assignement at (IX + BC) + push ix + pop hl + add hl, bc + +__ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + +__STORE_STR: + push de ; Pointer to b$ + push hl ; Array pointer to variable memory address + + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation + ex de, hl ; DE = new address of a$ + pop hl ; Recover variable memory address pointer + + ld (hl), e + inc hl + ld (hl), d ; Stores a$ ptr into elemem ptr + + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) + ret + +#line 53 "let_array_substr11.bas" + +ZXBASIC_USER_DATA: +_a: + DEFW 0000h + DEFB 02h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/let_array_substr11.bas b/tests/functional/let_array_substr11.bas new file mode 100644 index 000000000..ba8cec2ca --- /dev/null +++ b/tests/functional/let_array_substr11.bas @@ -0,0 +1,4 @@ +DIM a$(10) +LET a(3) = "0123456789" +LET a(3, TO) = "HELLO" + diff --git a/tests/functional/let_array_substr12.asm b/tests/functional/let_array_substr12.asm new file mode 100644 index 000000000..7a02d0a5e --- /dev/null +++ b/tests/functional/let_array_substr12.asm @@ -0,0 +1,1155 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld de, __LABEL0 + ld hl, _a + 9 + call __STORE_STR + ld hl, __LABEL1 + call __LOADSTR + push hl + xor a + push af + ld hl, 5 + push hl + ld hl, 5 + push hl + ld hl, (_a + 9) + call __LETSUBSTR + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__LABEL0: + DEFW 000Ah + DEFB 30h + DEFB 31h + DEFB 32h + DEFB 33h + DEFB 34h + DEFB 35h + DEFB 36h + DEFB 37h + DEFB 38h + DEFB 39h +__LABEL1: + DEFW 0005h + DEFB 48h + DEFB 45h + DEFB 4Ch + DEFB 4Ch + DEFB 4Fh +#line 1 "letsubstr.asm" + + ; Substring assigment eg. LET a$(p0 TO p1) = "xxxx" + ; HL = Start of string + ; TOP of the stack -> p1 (16 bit, unsigned) + ; TOP -1 of the stack -> p0 register + ; TOP -2 Flag (popped out in A register) + ; A Register => 0 if HL is not freed from memory + ; => Not 0 if HL must be freed from memory on exit + ; TOP -3 B$ address + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 11 "letsubstr.asm" + +__LETSUBSTR: + PROC + + LOCAL __CONT0 + LOCAL __CONT1 + LOCAL __CONT2 + LOCAL __FREE_STR + LOCAL __FREE_STR0 + + exx + pop hl ; Return address + pop de ; p1 + pop bc ; p0 + exx + + pop af ; Flag + ex af, af' ; Save it for later + + pop de ; B$ + + exx + push hl ; push ret addr back + exx + + ld a, h + or l + jp z, __FREE_STR0 ; Return if null + + ld c, (hl) + inc hl + ld b, (hl) ; BC = Str length + inc hl ; HL = String start + push bc + + exx + ex de, hl + or a + sbc hl, bc ; HL = Length of string requester by user + inc hl ; len (a$(p0 TO p1)) = p1 - p0 + 1 + ex de, hl ; Saves it in DE + + pop hl ; HL = String length + exx + jp c, __FREE_STR0 ; Return if greather + exx ; Return if p0 > p1 + + or a + sbc hl, bc ; P0 >= String length? + exx + + jp z, __FREE_STR0 ; Return if equal + jp c, __FREE_STR0 ; Return if greather + + exx + add hl, bc ; Add it back + + sbc hl, de ; Length of substring > string => Truncate it + add hl, de ; add it back + jr nc, __CONT0 ; Length of substring within a$ + + ld d, h + ld e, l ; Truncate length of substring to fit within the strlen + +__CONT0: ; At this point DE = Length of subtring to copy + ; BC = start of char to copy + push de + + push bc + exx + pop bc + + add hl, bc ; Start address (within a$) so copy from b$ (in DE) + + push hl + exx + pop hl ; Start address (within a$) so copy from b$ (in DE) + + ld b, d ; Length of string + ld c, e + + ld (hl), ' ' + ld d, h + ld e, l + inc de + dec bc + ld a, b + or c + jr z, __CONT2 + + ; At this point HL = DE = Start of Write zone in a$ + ; BC = Number of chars to write + + ldir + +__CONT2: + + pop bc ; Recovers Length of string to copy + exx + ex de, hl ; HL = Source, DE = Target + + ld a, h + or l + jp z, __FREE_STR ; Return if B$ is NULL + + ld c, (hl) + inc hl + ld b, (hl) + inc hl + + ld a, b + or c + jp z, __FREE_STR ; Return if len(b$) = 0 + + ; Now if len(b$) < len(char to copy), copy only len(b$) chars + + push de + push hl + push bc + exx + pop hl ; LEN (b$) + or a + sbc hl, bc + add hl, bc + jr nc, __CONT1 + + ; If len(b$) < len(to copy) + ld b, h ; BC = len(to copy) + ld c, l + +__CONT1: + pop hl + pop de + ldir ; Copy b$ into a$(x to y) + + exx + ex de, hl + +__FREE_STR0: + ex de, hl + +__FREE_STR: + ex af, af' + or a ; If not 0, free + jp nz, __MEM_FREE + ret + + ENDP + +#line 51 "let_array_substr12.bas" +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 69 "alloc.asm" + + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 52 "let_array_substr12.bas" +#line 1 "storestr.asm" + +; vim:ts=4:et:sw=4 + ; Stores value of current string pointed by DE register into address pointed by HL + ; Returns DE = Address pointer (&a$) + ; Returns HL = HL (b$ => might be needed later to free it from the heap) + ; + ; e.g. => HL = _variableName (DIM _variableName$) + ; DE = Address into the HEAP + ; + ; This function will resize (REALLOC) the space pointed by HL + ; before copying the content of b$ into a$ + + +#line 1 "strcpy.asm" + +#line 1 "realloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + + + + ; --------------------------------------------------------------------- + ; MEM_REALLOC + ; Reallocates a block of memory in the heap. + ; + ; Parameters + ; HL = Pointer to the original block + ; BC = New Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; +; Notes: + ; If BC = 0, the block is freed, otherwise + ; the content of the original block is copied to the new one, and + ; the new size is adjusted. If BC < original length, the content + ; will be truncated. Otherwise, extra block content might contain + ; memory garbage. + ; + ; --------------------------------------------------------------------- +__REALLOC: ; Reallocates block pointed by HL, with new length BC + PROC + + LOCAL __REALLOC_END + + ld a, h + or l + jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc + + ld e, (hl) + inc hl + ld d, (hl) ; DE = First 2 bytes of HL block + + push hl + exx + pop de + inc de ; DE' <- HL + 2 + exx ; DE' <- HL (Saves current pointer into DE') + + dec hl ; HL = Block start + + push de + push bc + call __MEM_FREE ; Frees current block + pop bc + push bc + call __MEM_ALLOC ; Gets a new block of length BC + pop bc + pop de + + ld a, h + or l + ret z ; Return if HL == NULL (No memory) + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Recovers first 2 bytes in HL + + dec bc + dec bc ; BC = BC - 2 (Two bytes copied) + + ld a, b + or c + jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) + + exx + push de + exx + pop de ; DE <- DE' ; Start of remaining block + + push hl ; Saves current Block + 2 start + ex de, hl ; Exchanges them: DE is destiny block + ldir ; Copies BC Bytes + pop hl ; Recovers Block + 2 start + +__REALLOC_END: + + dec hl ; Set HL + dec hl ; To begin of block + ret + + ENDP + +#line 2 "strcpy.asm" + + ; String library + + +__STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) + PROC + + LOCAL __STRREALLOC + LOCAL __STRCONTINUE + LOCAL __B_IS_NULL + LOCAL __NOTHING_TO_COPY + + ld b, d + ld c, e + ld a, b + or c + jr z, __B_IS_NULL + + ex de, hl + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(b$) + ex de, hl ; DE = &b$ + +__B_IS_NULL: ; Jumps here if B$ pointer is NULL + inc bc + inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) + + push de + push hl + + ld a, h + or l + jr z, __STRREALLOC + + dec hl + ld d, (hl) + dec hl + ld e, (hl) ; DE = MEMBLOCKSIZE(a$) + dec de + dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) + + ld h, b + ld l, c ; HL = LEN(b$) + 2 => Minimum block size required + ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 + + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) + sbc hl, de ; Carry if len(b$) > Blocklen(a$) + jr c, __STRREALLOC ; No need to realloc + ; Need to reallocate at least to len(b$) + 2 + ex de, hl ; DE = Remaining bytes in a$ mem block. + ld hl, 4 + sbc hl, de ; if remaining bytes < 4 we can continue + jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes + +__STRREALLOC: + pop hl + call __REALLOC ; Returns in HL a new pointer with BC bytes allocated + push hl + +__STRCONTINUE: ; Pops hl and de SWAPPED + pop de ; DE = &a$ + pop hl ; HL = &b$ + + ld a, d ; Return if not enough memory for new length + or e + ret z ; Return if DE == NULL (0) + +__STRCPY: ; Copies string pointed by HL into string pointed by DE + ; Returns DE as HL (new pointer) + ld a, h + or l + jr z, __NOTHING_TO_COPY + ld c, (hl) + inc hl + ld b, (hl) + dec hl + inc bc + inc bc + push de + ldir + pop hl + ret + +__NOTHING_TO_COPY: + ex de, hl + ld (hl), e + inc hl + ld (hl), d + dec hl + ret + + ENDP + +#line 14 "storestr.asm" + +__PISTORE_STR: ; Indirect assignement at (IX + BC) + push ix + pop hl + add hl, bc + +__ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + +__STORE_STR: + push de ; Pointer to b$ + push hl ; Array pointer to variable memory address + + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation + ex de, hl ; DE = new address of a$ + pop hl ; Recover variable memory address pointer + + ld (hl), e + inc hl + ld (hl), d ; Stores a$ ptr into elemem ptr + + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) + ret + +#line 53 "let_array_substr12.bas" + +ZXBASIC_USER_DATA: +_a: + DEFW 0000h + DEFB 02h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/let_array_substr12.bas b/tests/functional/let_array_substr12.bas new file mode 100644 index 000000000..03bd92466 --- /dev/null +++ b/tests/functional/let_array_substr12.bas @@ -0,0 +1,4 @@ +DIM a$(10) +LET a(3) = "0123456789" +LET a(3, 5 TO 5) = "HELLO" + diff --git a/tests/functional/let_array_substr13.asm b/tests/functional/let_array_substr13.asm new file mode 100644 index 000000000..cc97b2105 --- /dev/null +++ b/tests/functional/let_array_substr13.asm @@ -0,0 +1,1155 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld de, __LABEL0 + ld hl, _a + 9 + call __STORE_STR + ld hl, __LABEL1 + call __LOADSTR + push hl + xor a + push af + ld hl, 5 + push hl + ld hl, 5 + push hl + ld hl, (_a + 9) + call __LETSUBSTR + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__LABEL0: + DEFW 000Ah + DEFB 30h + DEFB 31h + DEFB 32h + DEFB 33h + DEFB 34h + DEFB 35h + DEFB 36h + DEFB 37h + DEFB 38h + DEFB 39h +__LABEL1: + DEFW 0005h + DEFB 48h + DEFB 45h + DEFB 4Ch + DEFB 4Ch + DEFB 4Fh +#line 1 "letsubstr.asm" + + ; Substring assigment eg. LET a$(p0 TO p1) = "xxxx" + ; HL = Start of string + ; TOP of the stack -> p1 (16 bit, unsigned) + ; TOP -1 of the stack -> p0 register + ; TOP -2 Flag (popped out in A register) + ; A Register => 0 if HL is not freed from memory + ; => Not 0 if HL must be freed from memory on exit + ; TOP -3 B$ address + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 11 "letsubstr.asm" + +__LETSUBSTR: + PROC + + LOCAL __CONT0 + LOCAL __CONT1 + LOCAL __CONT2 + LOCAL __FREE_STR + LOCAL __FREE_STR0 + + exx + pop hl ; Return address + pop de ; p1 + pop bc ; p0 + exx + + pop af ; Flag + ex af, af' ; Save it for later + + pop de ; B$ + + exx + push hl ; push ret addr back + exx + + ld a, h + or l + jp z, __FREE_STR0 ; Return if null + + ld c, (hl) + inc hl + ld b, (hl) ; BC = Str length + inc hl ; HL = String start + push bc + + exx + ex de, hl + or a + sbc hl, bc ; HL = Length of string requester by user + inc hl ; len (a$(p0 TO p1)) = p1 - p0 + 1 + ex de, hl ; Saves it in DE + + pop hl ; HL = String length + exx + jp c, __FREE_STR0 ; Return if greather + exx ; Return if p0 > p1 + + or a + sbc hl, bc ; P0 >= String length? + exx + + jp z, __FREE_STR0 ; Return if equal + jp c, __FREE_STR0 ; Return if greather + + exx + add hl, bc ; Add it back + + sbc hl, de ; Length of substring > string => Truncate it + add hl, de ; add it back + jr nc, __CONT0 ; Length of substring within a$ + + ld d, h + ld e, l ; Truncate length of substring to fit within the strlen + +__CONT0: ; At this point DE = Length of subtring to copy + ; BC = start of char to copy + push de + + push bc + exx + pop bc + + add hl, bc ; Start address (within a$) so copy from b$ (in DE) + + push hl + exx + pop hl ; Start address (within a$) so copy from b$ (in DE) + + ld b, d ; Length of string + ld c, e + + ld (hl), ' ' + ld d, h + ld e, l + inc de + dec bc + ld a, b + or c + jr z, __CONT2 + + ; At this point HL = DE = Start of Write zone in a$ + ; BC = Number of chars to write + + ldir + +__CONT2: + + pop bc ; Recovers Length of string to copy + exx + ex de, hl ; HL = Source, DE = Target + + ld a, h + or l + jp z, __FREE_STR ; Return if B$ is NULL + + ld c, (hl) + inc hl + ld b, (hl) + inc hl + + ld a, b + or c + jp z, __FREE_STR ; Return if len(b$) = 0 + + ; Now if len(b$) < len(char to copy), copy only len(b$) chars + + push de + push hl + push bc + exx + pop hl ; LEN (b$) + or a + sbc hl, bc + add hl, bc + jr nc, __CONT1 + + ; If len(b$) < len(to copy) + ld b, h ; BC = len(to copy) + ld c, l + +__CONT1: + pop hl + pop de + ldir ; Copy b$ into a$(x to y) + + exx + ex de, hl + +__FREE_STR0: + ex de, hl + +__FREE_STR: + ex af, af' + or a ; If not 0, free + jp nz, __MEM_FREE + ret + + ENDP + +#line 51 "let_array_substr13.bas" +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 69 "alloc.asm" + + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 52 "let_array_substr13.bas" +#line 1 "storestr.asm" + +; vim:ts=4:et:sw=4 + ; Stores value of current string pointed by DE register into address pointed by HL + ; Returns DE = Address pointer (&a$) + ; Returns HL = HL (b$ => might be needed later to free it from the heap) + ; + ; e.g. => HL = _variableName (DIM _variableName$) + ; DE = Address into the HEAP + ; + ; This function will resize (REALLOC) the space pointed by HL + ; before copying the content of b$ into a$ + + +#line 1 "strcpy.asm" + +#line 1 "realloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + + + + ; --------------------------------------------------------------------- + ; MEM_REALLOC + ; Reallocates a block of memory in the heap. + ; + ; Parameters + ; HL = Pointer to the original block + ; BC = New Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; +; Notes: + ; If BC = 0, the block is freed, otherwise + ; the content of the original block is copied to the new one, and + ; the new size is adjusted. If BC < original length, the content + ; will be truncated. Otherwise, extra block content might contain + ; memory garbage. + ; + ; --------------------------------------------------------------------- +__REALLOC: ; Reallocates block pointed by HL, with new length BC + PROC + + LOCAL __REALLOC_END + + ld a, h + or l + jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc + + ld e, (hl) + inc hl + ld d, (hl) ; DE = First 2 bytes of HL block + + push hl + exx + pop de + inc de ; DE' <- HL + 2 + exx ; DE' <- HL (Saves current pointer into DE') + + dec hl ; HL = Block start + + push de + push bc + call __MEM_FREE ; Frees current block + pop bc + push bc + call __MEM_ALLOC ; Gets a new block of length BC + pop bc + pop de + + ld a, h + or l + ret z ; Return if HL == NULL (No memory) + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Recovers first 2 bytes in HL + + dec bc + dec bc ; BC = BC - 2 (Two bytes copied) + + ld a, b + or c + jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) + + exx + push de + exx + pop de ; DE <- DE' ; Start of remaining block + + push hl ; Saves current Block + 2 start + ex de, hl ; Exchanges them: DE is destiny block + ldir ; Copies BC Bytes + pop hl ; Recovers Block + 2 start + +__REALLOC_END: + + dec hl ; Set HL + dec hl ; To begin of block + ret + + ENDP + +#line 2 "strcpy.asm" + + ; String library + + +__STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) + PROC + + LOCAL __STRREALLOC + LOCAL __STRCONTINUE + LOCAL __B_IS_NULL + LOCAL __NOTHING_TO_COPY + + ld b, d + ld c, e + ld a, b + or c + jr z, __B_IS_NULL + + ex de, hl + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(b$) + ex de, hl ; DE = &b$ + +__B_IS_NULL: ; Jumps here if B$ pointer is NULL + inc bc + inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) + + push de + push hl + + ld a, h + or l + jr z, __STRREALLOC + + dec hl + ld d, (hl) + dec hl + ld e, (hl) ; DE = MEMBLOCKSIZE(a$) + dec de + dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) + + ld h, b + ld l, c ; HL = LEN(b$) + 2 => Minimum block size required + ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 + + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) + sbc hl, de ; Carry if len(b$) > Blocklen(a$) + jr c, __STRREALLOC ; No need to realloc + ; Need to reallocate at least to len(b$) + 2 + ex de, hl ; DE = Remaining bytes in a$ mem block. + ld hl, 4 + sbc hl, de ; if remaining bytes < 4 we can continue + jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes + +__STRREALLOC: + pop hl + call __REALLOC ; Returns in HL a new pointer with BC bytes allocated + push hl + +__STRCONTINUE: ; Pops hl and de SWAPPED + pop de ; DE = &a$ + pop hl ; HL = &b$ + + ld a, d ; Return if not enough memory for new length + or e + ret z ; Return if DE == NULL (0) + +__STRCPY: ; Copies string pointed by HL into string pointed by DE + ; Returns DE as HL (new pointer) + ld a, h + or l + jr z, __NOTHING_TO_COPY + ld c, (hl) + inc hl + ld b, (hl) + dec hl + inc bc + inc bc + push de + ldir + pop hl + ret + +__NOTHING_TO_COPY: + ex de, hl + ld (hl), e + inc hl + ld (hl), d + dec hl + ret + + ENDP + +#line 14 "storestr.asm" + +__PISTORE_STR: ; Indirect assignement at (IX + BC) + push ix + pop hl + add hl, bc + +__ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + +__STORE_STR: + push de ; Pointer to b$ + push hl ; Array pointer to variable memory address + + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation + ex de, hl ; DE = new address of a$ + pop hl ; Recover variable memory address pointer + + ld (hl), e + inc hl + ld (hl), d ; Stores a$ ptr into elemem ptr + + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) + ret + +#line 53 "let_array_substr13.bas" + +ZXBASIC_USER_DATA: +_a: + DEFW 0000h + DEFB 02h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/let_array_substr13.bas b/tests/functional/let_array_substr13.bas new file mode 100644 index 000000000..bd5a50ffa --- /dev/null +++ b/tests/functional/let_array_substr13.bas @@ -0,0 +1,4 @@ +DIM a$(10) +LET a(3) = "0123456789" +LET a(3, 5) = "HELLO" + diff --git a/tests/functional/let_array_substr2.asm b/tests/functional/let_array_substr2.asm new file mode 100644 index 000000000..7e8e0221b --- /dev/null +++ b/tests/functional/let_array_substr2.asm @@ -0,0 +1,1155 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld de, __LABEL0 + ld hl, _a + 9 + call __STORE_STR + ld hl, __LABEL1 + call __LOADSTR + push hl + xor a + push af + ld hl, 1 + push hl + ld hl, 5 + push hl + ld hl, (_a + 9) + call __LETSUBSTR + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__LABEL0: + DEFW 000Ah + DEFB 30h + DEFB 31h + DEFB 32h + DEFB 33h + DEFB 34h + DEFB 35h + DEFB 36h + DEFB 37h + DEFB 38h + DEFB 39h +__LABEL1: + DEFW 0005h + DEFB 48h + DEFB 45h + DEFB 4Ch + DEFB 4Ch + DEFB 4Fh +#line 1 "letsubstr.asm" + + ; Substring assigment eg. LET a$(p0 TO p1) = "xxxx" + ; HL = Start of string + ; TOP of the stack -> p1 (16 bit, unsigned) + ; TOP -1 of the stack -> p0 register + ; TOP -2 Flag (popped out in A register) + ; A Register => 0 if HL is not freed from memory + ; => Not 0 if HL must be freed from memory on exit + ; TOP -3 B$ address + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 11 "letsubstr.asm" + +__LETSUBSTR: + PROC + + LOCAL __CONT0 + LOCAL __CONT1 + LOCAL __CONT2 + LOCAL __FREE_STR + LOCAL __FREE_STR0 + + exx + pop hl ; Return address + pop de ; p1 + pop bc ; p0 + exx + + pop af ; Flag + ex af, af' ; Save it for later + + pop de ; B$ + + exx + push hl ; push ret addr back + exx + + ld a, h + or l + jp z, __FREE_STR0 ; Return if null + + ld c, (hl) + inc hl + ld b, (hl) ; BC = Str length + inc hl ; HL = String start + push bc + + exx + ex de, hl + or a + sbc hl, bc ; HL = Length of string requester by user + inc hl ; len (a$(p0 TO p1)) = p1 - p0 + 1 + ex de, hl ; Saves it in DE + + pop hl ; HL = String length + exx + jp c, __FREE_STR0 ; Return if greather + exx ; Return if p0 > p1 + + or a + sbc hl, bc ; P0 >= String length? + exx + + jp z, __FREE_STR0 ; Return if equal + jp c, __FREE_STR0 ; Return if greather + + exx + add hl, bc ; Add it back + + sbc hl, de ; Length of substring > string => Truncate it + add hl, de ; add it back + jr nc, __CONT0 ; Length of substring within a$ + + ld d, h + ld e, l ; Truncate length of substring to fit within the strlen + +__CONT0: ; At this point DE = Length of subtring to copy + ; BC = start of char to copy + push de + + push bc + exx + pop bc + + add hl, bc ; Start address (within a$) so copy from b$ (in DE) + + push hl + exx + pop hl ; Start address (within a$) so copy from b$ (in DE) + + ld b, d ; Length of string + ld c, e + + ld (hl), ' ' + ld d, h + ld e, l + inc de + dec bc + ld a, b + or c + jr z, __CONT2 + + ; At this point HL = DE = Start of Write zone in a$ + ; BC = Number of chars to write + + ldir + +__CONT2: + + pop bc ; Recovers Length of string to copy + exx + ex de, hl ; HL = Source, DE = Target + + ld a, h + or l + jp z, __FREE_STR ; Return if B$ is NULL + + ld c, (hl) + inc hl + ld b, (hl) + inc hl + + ld a, b + or c + jp z, __FREE_STR ; Return if len(b$) = 0 + + ; Now if len(b$) < len(char to copy), copy only len(b$) chars + + push de + push hl + push bc + exx + pop hl ; LEN (b$) + or a + sbc hl, bc + add hl, bc + jr nc, __CONT1 + + ; If len(b$) < len(to copy) + ld b, h ; BC = len(to copy) + ld c, l + +__CONT1: + pop hl + pop de + ldir ; Copy b$ into a$(x to y) + + exx + ex de, hl + +__FREE_STR0: + ex de, hl + +__FREE_STR: + ex af, af' + or a ; If not 0, free + jp nz, __MEM_FREE + ret + + ENDP + +#line 51 "let_array_substr2.bas" +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 69 "alloc.asm" + + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 52 "let_array_substr2.bas" +#line 1 "storestr.asm" + +; vim:ts=4:et:sw=4 + ; Stores value of current string pointed by DE register into address pointed by HL + ; Returns DE = Address pointer (&a$) + ; Returns HL = HL (b$ => might be needed later to free it from the heap) + ; + ; e.g. => HL = _variableName (DIM _variableName$) + ; DE = Address into the HEAP + ; + ; This function will resize (REALLOC) the space pointed by HL + ; before copying the content of b$ into a$ + + +#line 1 "strcpy.asm" + +#line 1 "realloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + + + + ; --------------------------------------------------------------------- + ; MEM_REALLOC + ; Reallocates a block of memory in the heap. + ; + ; Parameters + ; HL = Pointer to the original block + ; BC = New Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; +; Notes: + ; If BC = 0, the block is freed, otherwise + ; the content of the original block is copied to the new one, and + ; the new size is adjusted. If BC < original length, the content + ; will be truncated. Otherwise, extra block content might contain + ; memory garbage. + ; + ; --------------------------------------------------------------------- +__REALLOC: ; Reallocates block pointed by HL, with new length BC + PROC + + LOCAL __REALLOC_END + + ld a, h + or l + jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc + + ld e, (hl) + inc hl + ld d, (hl) ; DE = First 2 bytes of HL block + + push hl + exx + pop de + inc de ; DE' <- HL + 2 + exx ; DE' <- HL (Saves current pointer into DE') + + dec hl ; HL = Block start + + push de + push bc + call __MEM_FREE ; Frees current block + pop bc + push bc + call __MEM_ALLOC ; Gets a new block of length BC + pop bc + pop de + + ld a, h + or l + ret z ; Return if HL == NULL (No memory) + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Recovers first 2 bytes in HL + + dec bc + dec bc ; BC = BC - 2 (Two bytes copied) + + ld a, b + or c + jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) + + exx + push de + exx + pop de ; DE <- DE' ; Start of remaining block + + push hl ; Saves current Block + 2 start + ex de, hl ; Exchanges them: DE is destiny block + ldir ; Copies BC Bytes + pop hl ; Recovers Block + 2 start + +__REALLOC_END: + + dec hl ; Set HL + dec hl ; To begin of block + ret + + ENDP + +#line 2 "strcpy.asm" + + ; String library + + +__STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) + PROC + + LOCAL __STRREALLOC + LOCAL __STRCONTINUE + LOCAL __B_IS_NULL + LOCAL __NOTHING_TO_COPY + + ld b, d + ld c, e + ld a, b + or c + jr z, __B_IS_NULL + + ex de, hl + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(b$) + ex de, hl ; DE = &b$ + +__B_IS_NULL: ; Jumps here if B$ pointer is NULL + inc bc + inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) + + push de + push hl + + ld a, h + or l + jr z, __STRREALLOC + + dec hl + ld d, (hl) + dec hl + ld e, (hl) ; DE = MEMBLOCKSIZE(a$) + dec de + dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) + + ld h, b + ld l, c ; HL = LEN(b$) + 2 => Minimum block size required + ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 + + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) + sbc hl, de ; Carry if len(b$) > Blocklen(a$) + jr c, __STRREALLOC ; No need to realloc + ; Need to reallocate at least to len(b$) + 2 + ex de, hl ; DE = Remaining bytes in a$ mem block. + ld hl, 4 + sbc hl, de ; if remaining bytes < 4 we can continue + jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes + +__STRREALLOC: + pop hl + call __REALLOC ; Returns in HL a new pointer with BC bytes allocated + push hl + +__STRCONTINUE: ; Pops hl and de SWAPPED + pop de ; DE = &a$ + pop hl ; HL = &b$ + + ld a, d ; Return if not enough memory for new length + or e + ret z ; Return if DE == NULL (0) + +__STRCPY: ; Copies string pointed by HL into string pointed by DE + ; Returns DE as HL (new pointer) + ld a, h + or l + jr z, __NOTHING_TO_COPY + ld c, (hl) + inc hl + ld b, (hl) + dec hl + inc bc + inc bc + push de + ldir + pop hl + ret + +__NOTHING_TO_COPY: + ex de, hl + ld (hl), e + inc hl + ld (hl), d + dec hl + ret + + ENDP + +#line 14 "storestr.asm" + +__PISTORE_STR: ; Indirect assignement at (IX + BC) + push ix + pop hl + add hl, bc + +__ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + +__STORE_STR: + push de ; Pointer to b$ + push hl ; Array pointer to variable memory address + + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation + ex de, hl ; DE = new address of a$ + pop hl ; Recover variable memory address pointer + + ld (hl), e + inc hl + ld (hl), d ; Stores a$ ptr into elemem ptr + + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) + ret + +#line 53 "let_array_substr2.bas" + +ZXBASIC_USER_DATA: +_a: + DEFW 0000h + DEFB 02h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/let_array_substr2.bas b/tests/functional/let_array_substr2.bas new file mode 100644 index 000000000..658c8dab6 --- /dev/null +++ b/tests/functional/let_array_substr2.bas @@ -0,0 +1,4 @@ +DIM a$(10) +LET a$(3) = "0123456789" +LET a$(3)(1 TO 5) = "HELLO" + diff --git a/tests/functional/let_array_substr3.asm b/tests/functional/let_array_substr3.asm new file mode 100644 index 000000000..7dbc87a87 --- /dev/null +++ b/tests/functional/let_array_substr3.asm @@ -0,0 +1,1155 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld de, __LABEL0 + ld hl, _a + 9 + call __STORE_STR + ld hl, __LABEL1 + call __LOADSTR + push hl + xor a + push af + ld hl, 1 + push hl + ld hl, 5 + push hl + ld hl, (_a + 9) + call __LETSUBSTR + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__LABEL0: + DEFW 000Ah + DEFB 30h + DEFB 31h + DEFB 32h + DEFB 33h + DEFB 34h + DEFB 35h + DEFB 36h + DEFB 37h + DEFB 38h + DEFB 39h +__LABEL1: + DEFW 0005h + DEFB 48h + DEFB 45h + DEFB 4Ch + DEFB 4Ch + DEFB 4Fh +#line 1 "letsubstr.asm" + + ; Substring assigment eg. LET a$(p0 TO p1) = "xxxx" + ; HL = Start of string + ; TOP of the stack -> p1 (16 bit, unsigned) + ; TOP -1 of the stack -> p0 register + ; TOP -2 Flag (popped out in A register) + ; A Register => 0 if HL is not freed from memory + ; => Not 0 if HL must be freed from memory on exit + ; TOP -3 B$ address + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 11 "letsubstr.asm" + +__LETSUBSTR: + PROC + + LOCAL __CONT0 + LOCAL __CONT1 + LOCAL __CONT2 + LOCAL __FREE_STR + LOCAL __FREE_STR0 + + exx + pop hl ; Return address + pop de ; p1 + pop bc ; p0 + exx + + pop af ; Flag + ex af, af' ; Save it for later + + pop de ; B$ + + exx + push hl ; push ret addr back + exx + + ld a, h + or l + jp z, __FREE_STR0 ; Return if null + + ld c, (hl) + inc hl + ld b, (hl) ; BC = Str length + inc hl ; HL = String start + push bc + + exx + ex de, hl + or a + sbc hl, bc ; HL = Length of string requester by user + inc hl ; len (a$(p0 TO p1)) = p1 - p0 + 1 + ex de, hl ; Saves it in DE + + pop hl ; HL = String length + exx + jp c, __FREE_STR0 ; Return if greather + exx ; Return if p0 > p1 + + or a + sbc hl, bc ; P0 >= String length? + exx + + jp z, __FREE_STR0 ; Return if equal + jp c, __FREE_STR0 ; Return if greather + + exx + add hl, bc ; Add it back + + sbc hl, de ; Length of substring > string => Truncate it + add hl, de ; add it back + jr nc, __CONT0 ; Length of substring within a$ + + ld d, h + ld e, l ; Truncate length of substring to fit within the strlen + +__CONT0: ; At this point DE = Length of subtring to copy + ; BC = start of char to copy + push de + + push bc + exx + pop bc + + add hl, bc ; Start address (within a$) so copy from b$ (in DE) + + push hl + exx + pop hl ; Start address (within a$) so copy from b$ (in DE) + + ld b, d ; Length of string + ld c, e + + ld (hl), ' ' + ld d, h + ld e, l + inc de + dec bc + ld a, b + or c + jr z, __CONT2 + + ; At this point HL = DE = Start of Write zone in a$ + ; BC = Number of chars to write + + ldir + +__CONT2: + + pop bc ; Recovers Length of string to copy + exx + ex de, hl ; HL = Source, DE = Target + + ld a, h + or l + jp z, __FREE_STR ; Return if B$ is NULL + + ld c, (hl) + inc hl + ld b, (hl) + inc hl + + ld a, b + or c + jp z, __FREE_STR ; Return if len(b$) = 0 + + ; Now if len(b$) < len(char to copy), copy only len(b$) chars + + push de + push hl + push bc + exx + pop hl ; LEN (b$) + or a + sbc hl, bc + add hl, bc + jr nc, __CONT1 + + ; If len(b$) < len(to copy) + ld b, h ; BC = len(to copy) + ld c, l + +__CONT1: + pop hl + pop de + ldir ; Copy b$ into a$(x to y) + + exx + ex de, hl + +__FREE_STR0: + ex de, hl + +__FREE_STR: + ex af, af' + or a ; If not 0, free + jp nz, __MEM_FREE + ret + + ENDP + +#line 51 "let_array_substr3.bas" +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 69 "alloc.asm" + + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 52 "let_array_substr3.bas" +#line 1 "storestr.asm" + +; vim:ts=4:et:sw=4 + ; Stores value of current string pointed by DE register into address pointed by HL + ; Returns DE = Address pointer (&a$) + ; Returns HL = HL (b$ => might be needed later to free it from the heap) + ; + ; e.g. => HL = _variableName (DIM _variableName$) + ; DE = Address into the HEAP + ; + ; This function will resize (REALLOC) the space pointed by HL + ; before copying the content of b$ into a$ + + +#line 1 "strcpy.asm" + +#line 1 "realloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + + + + ; --------------------------------------------------------------------- + ; MEM_REALLOC + ; Reallocates a block of memory in the heap. + ; + ; Parameters + ; HL = Pointer to the original block + ; BC = New Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; +; Notes: + ; If BC = 0, the block is freed, otherwise + ; the content of the original block is copied to the new one, and + ; the new size is adjusted. If BC < original length, the content + ; will be truncated. Otherwise, extra block content might contain + ; memory garbage. + ; + ; --------------------------------------------------------------------- +__REALLOC: ; Reallocates block pointed by HL, with new length BC + PROC + + LOCAL __REALLOC_END + + ld a, h + or l + jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc + + ld e, (hl) + inc hl + ld d, (hl) ; DE = First 2 bytes of HL block + + push hl + exx + pop de + inc de ; DE' <- HL + 2 + exx ; DE' <- HL (Saves current pointer into DE') + + dec hl ; HL = Block start + + push de + push bc + call __MEM_FREE ; Frees current block + pop bc + push bc + call __MEM_ALLOC ; Gets a new block of length BC + pop bc + pop de + + ld a, h + or l + ret z ; Return if HL == NULL (No memory) + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Recovers first 2 bytes in HL + + dec bc + dec bc ; BC = BC - 2 (Two bytes copied) + + ld a, b + or c + jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) + + exx + push de + exx + pop de ; DE <- DE' ; Start of remaining block + + push hl ; Saves current Block + 2 start + ex de, hl ; Exchanges them: DE is destiny block + ldir ; Copies BC Bytes + pop hl ; Recovers Block + 2 start + +__REALLOC_END: + + dec hl ; Set HL + dec hl ; To begin of block + ret + + ENDP + +#line 2 "strcpy.asm" + + ; String library + + +__STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) + PROC + + LOCAL __STRREALLOC + LOCAL __STRCONTINUE + LOCAL __B_IS_NULL + LOCAL __NOTHING_TO_COPY + + ld b, d + ld c, e + ld a, b + or c + jr z, __B_IS_NULL + + ex de, hl + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(b$) + ex de, hl ; DE = &b$ + +__B_IS_NULL: ; Jumps here if B$ pointer is NULL + inc bc + inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) + + push de + push hl + + ld a, h + or l + jr z, __STRREALLOC + + dec hl + ld d, (hl) + dec hl + ld e, (hl) ; DE = MEMBLOCKSIZE(a$) + dec de + dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) + + ld h, b + ld l, c ; HL = LEN(b$) + 2 => Minimum block size required + ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 + + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) + sbc hl, de ; Carry if len(b$) > Blocklen(a$) + jr c, __STRREALLOC ; No need to realloc + ; Need to reallocate at least to len(b$) + 2 + ex de, hl ; DE = Remaining bytes in a$ mem block. + ld hl, 4 + sbc hl, de ; if remaining bytes < 4 we can continue + jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes + +__STRREALLOC: + pop hl + call __REALLOC ; Returns in HL a new pointer with BC bytes allocated + push hl + +__STRCONTINUE: ; Pops hl and de SWAPPED + pop de ; DE = &a$ + pop hl ; HL = &b$ + + ld a, d ; Return if not enough memory for new length + or e + ret z ; Return if DE == NULL (0) + +__STRCPY: ; Copies string pointed by HL into string pointed by DE + ; Returns DE as HL (new pointer) + ld a, h + or l + jr z, __NOTHING_TO_COPY + ld c, (hl) + inc hl + ld b, (hl) + dec hl + inc bc + inc bc + push de + ldir + pop hl + ret + +__NOTHING_TO_COPY: + ex de, hl + ld (hl), e + inc hl + ld (hl), d + dec hl + ret + + ENDP + +#line 14 "storestr.asm" + +__PISTORE_STR: ; Indirect assignement at (IX + BC) + push ix + pop hl + add hl, bc + +__ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + +__STORE_STR: + push de ; Pointer to b$ + push hl ; Array pointer to variable memory address + + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation + ex de, hl ; DE = new address of a$ + pop hl ; Recover variable memory address pointer + + ld (hl), e + inc hl + ld (hl), d ; Stores a$ ptr into elemem ptr + + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) + ret + +#line 53 "let_array_substr3.bas" + +ZXBASIC_USER_DATA: +_a: + DEFW 0000h + DEFB 02h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/let_array_substr3.bas b/tests/functional/let_array_substr3.bas new file mode 100644 index 000000000..b806f81f8 --- /dev/null +++ b/tests/functional/let_array_substr3.bas @@ -0,0 +1,4 @@ +DIM a$(10) +LET a$(3) = "0123456789" +a$(3)(1 TO 5) = "HELLO" + diff --git a/tests/functional/let_array_substr4.bas b/tests/functional/let_array_substr4.bas new file mode 100644 index 000000000..0c102974c --- /dev/null +++ b/tests/functional/let_array_substr4.bas @@ -0,0 +1,3 @@ +DIM a(10) as UInteger +LET a(3)(1 TO 5) = 4 + diff --git a/tests/functional/let_array_substr5.asm b/tests/functional/let_array_substr5.asm new file mode 100644 index 000000000..224ac4e01 --- /dev/null +++ b/tests/functional/let_array_substr5.asm @@ -0,0 +1,1371 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld hl, (_b) + push hl + ld hl, _a + call __ARRAY + ld de, __LABEL0 + call __STORE_STR + ld hl, __LABEL1 + call __LOADSTR + push hl + xor a + push af + ld hl, 1 + push hl + ld hl, 1 + push hl + ld hl, (_b) + push hl + ld hl, _a + call __ARRAY + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + call __LETSUBSTR + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__LABEL0: + DEFW 000Ah + DEFB 30h + DEFB 31h + DEFB 32h + DEFB 33h + DEFB 34h + DEFB 35h + DEFB 36h + DEFB 37h + DEFB 38h + DEFB 39h +__LABEL1: + DEFW 0005h + DEFB 48h + DEFB 45h + DEFB 4Ch + DEFB 4Ch + DEFB 4Fh +#line 1 "array.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; ------------------------------------------------------------------- + ; Simple array Index routine + ; Number of total indexes dimensions - 1 at beginning of memory + ; HL = Start of array memory (First two bytes contains N-1 dimensions) + ; Dimension values on the stack, (top of the stack, highest dimension) + ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> + + ; For any array of N dimension A(aN-1, ..., a1, a0) + ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as + ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] +; What I will do here is to calculate the following sequence: + ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... + + +#line 1 "mul16.asm" + +__MUL16: ; Mutiplies HL with the last value stored into de stack + ; Works for both signed and unsigned + + PROC + + LOCAL __MUL16LOOP + LOCAL __MUL16NOADD + + ex de, hl + pop hl ; Return address + ex (sp), hl ; CALLEE caller convention + +;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand + ;; ld c, h + ;; ld a, l ; C,A => 1st Operand + ;; + ;; ld hl, 0 ; Accumulator + ;; ld b, 16 + ;; +;;__MUL16LOOP: + ;; sra c ; C,A >> 1 (Arithmetic) + ;; rra + ;; + ;; jr nc, __MUL16NOADD + ;; add hl, de + ;; +;;__MUL16NOADD: + ;; sla e + ;; rl d + ;; + ;; djnz __MUL16LOOP + +__MUL16_FAST: + ld b, 16 + ld a, d + ld c, e + ex de, hl + ld hl, 0 + +__MUL16LOOP: + add hl, hl ; hl << 1 + sla c + rla ; a,c << 1 + jp nc, __MUL16NOADD + add hl, de + +__MUL16NOADD: + djnz __MUL16LOOP + + ret ; Result in hl (16 lower bits) + + ENDP + +#line 20 "array.asm" + +#line 24 "/src/zxb/trunk/library-asm/array.asm" + +__ARRAY: + PROC + + LOCAL LOOP + LOCAL ARRAY_END + LOCAL RET_ADDRESS ; Stores return address + + ex (sp), hl ; Return address in HL, array address in the stack + ld (RET_ADDRESS + 1), hl ; Stores it for later + + exx + pop hl ; Will use H'L' as the pointer + ld c, (hl) ; Loads Number of dimensions from (hl) + inc hl + ld b, (hl) + inc hl ; Ready + exx + + ld hl, 0 ; BC = Offset "accumulator" + +#line 48 "/src/zxb/trunk/library-asm/array.asm" + +LOOP: + pop bc ; Get next index (Ai) from the stack + +#line 60 "/src/zxb/trunk/library-asm/array.asm" + + add hl, bc ; Adds current index + + exx ; Checks if B'C' = 0 + ld a, b ; Which means we must exit (last element is not multiplied by anything) + or c + jr z, ARRAY_END ; if B'Ci == 0 we are done + + ld e, (hl) ; Loads next dimension into D'E' + inc hl + ld d, (hl) + inc hl + push de + dec bc ; Decrements loop counter + exx + pop de ; DE = Max bound Number (i-th dimension) + +#line 80 "/src/zxb/trunk/library-asm/array.asm" + ;call __MUL16_FAST ; HL *= DE + call __FNMUL +#line 86 "/src/zxb/trunk/library-asm/array.asm" + jp LOOP + +ARRAY_END: + ld e, (hl) + inc hl + ld d, c ; C = 0 => DE = E = Element size + push hl + push de + exx + +#line 100 "/src/zxb/trunk/library-asm/array.asm" + LOCAL ARRAY_SIZE_LOOP + + ex de, hl + ld hl, 0 + pop bc + ld b, c +ARRAY_SIZE_LOOP: + add hl, de + djnz ARRAY_SIZE_LOOP + + ;; Even faster + ;pop bc + + ;ld d, h + ;ld e, l + + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, hl + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, hl + ;dec c + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, de + ;__ARRAY_FIN: +#line 131 "/src/zxb/trunk/library-asm/array.asm" + + pop de + add hl, de ; Adds element start + +RET_ADDRESS: + ld de, 0 + push de + ret ; HL = (Start of Elements + Offset) + + ;; Performs a faster multiply for little 16bit numbs + LOCAL __FNMUL, __FNMUL2 + +__FNMUL: + xor a + or d + jp nz, __MUL16_FAST + + or e + ex de, hl + ret z + + cp 33 + jp nc, __MUL16_FAST + + ld b, l + ld l, h ; HL = 0 + +__FNMUL2: + add hl, de + djnz __FNMUL2 + ret + + ENDP + +#line 61 "let_array_substr5.bas" +#line 1 "letsubstr.asm" + + ; Substring assigment eg. LET a$(p0 TO p1) = "xxxx" + ; HL = Start of string + ; TOP of the stack -> p1 (16 bit, unsigned) + ; TOP -1 of the stack -> p0 register + ; TOP -2 Flag (popped out in A register) + ; A Register => 0 if HL is not freed from memory + ; => Not 0 if HL must be freed from memory on exit + ; TOP -3 B$ address + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 11 "letsubstr.asm" + +__LETSUBSTR: + PROC + + LOCAL __CONT0 + LOCAL __CONT1 + LOCAL __CONT2 + LOCAL __FREE_STR + LOCAL __FREE_STR0 + + exx + pop hl ; Return address + pop de ; p1 + pop bc ; p0 + exx + + pop af ; Flag + ex af, af' ; Save it for later + + pop de ; B$ + + exx + push hl ; push ret addr back + exx + + ld a, h + or l + jp z, __FREE_STR0 ; Return if null + + ld c, (hl) + inc hl + ld b, (hl) ; BC = Str length + inc hl ; HL = String start + push bc + + exx + ex de, hl + or a + sbc hl, bc ; HL = Length of string requester by user + inc hl ; len (a$(p0 TO p1)) = p1 - p0 + 1 + ex de, hl ; Saves it in DE + + pop hl ; HL = String length + exx + jp c, __FREE_STR0 ; Return if greather + exx ; Return if p0 > p1 + + or a + sbc hl, bc ; P0 >= String length? + exx + + jp z, __FREE_STR0 ; Return if equal + jp c, __FREE_STR0 ; Return if greather + + exx + add hl, bc ; Add it back + + sbc hl, de ; Length of substring > string => Truncate it + add hl, de ; add it back + jr nc, __CONT0 ; Length of substring within a$ + + ld d, h + ld e, l ; Truncate length of substring to fit within the strlen + +__CONT0: ; At this point DE = Length of subtring to copy + ; BC = start of char to copy + push de + + push bc + exx + pop bc + + add hl, bc ; Start address (within a$) so copy from b$ (in DE) + + push hl + exx + pop hl ; Start address (within a$) so copy from b$ (in DE) + + ld b, d ; Length of string + ld c, e + + ld (hl), ' ' + ld d, h + ld e, l + inc de + dec bc + ld a, b + or c + jr z, __CONT2 + + ; At this point HL = DE = Start of Write zone in a$ + ; BC = Number of chars to write + + ldir + +__CONT2: + + pop bc ; Recovers Length of string to copy + exx + ex de, hl ; HL = Source, DE = Target + + ld a, h + or l + jp z, __FREE_STR ; Return if B$ is NULL + + ld c, (hl) + inc hl + ld b, (hl) + inc hl + + ld a, b + or c + jp z, __FREE_STR ; Return if len(b$) = 0 + + ; Now if len(b$) < len(char to copy), copy only len(b$) chars + + push de + push hl + push bc + exx + pop hl ; LEN (b$) + or a + sbc hl, bc + add hl, bc + jr nc, __CONT1 + + ; If len(b$) < len(to copy) + ld b, h ; BC = len(to copy) + ld c, l + +__CONT1: + pop hl + pop de + ldir ; Copy b$ into a$(x to y) + + exx + ex de, hl + +__FREE_STR0: + ex de, hl + +__FREE_STR: + ex af, af' + or a ; If not 0, free + jp nz, __MEM_FREE + ret + + ENDP + +#line 62 "let_array_substr5.bas" +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 69 "alloc.asm" + + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 63 "let_array_substr5.bas" +#line 1 "storestr.asm" + +; vim:ts=4:et:sw=4 + ; Stores value of current string pointed by DE register into address pointed by HL + ; Returns DE = Address pointer (&a$) + ; Returns HL = HL (b$ => might be needed later to free it from the heap) + ; + ; e.g. => HL = _variableName (DIM _variableName$) + ; DE = Address into the HEAP + ; + ; This function will resize (REALLOC) the space pointed by HL + ; before copying the content of b$ into a$ + + +#line 1 "strcpy.asm" + +#line 1 "realloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + + + + ; --------------------------------------------------------------------- + ; MEM_REALLOC + ; Reallocates a block of memory in the heap. + ; + ; Parameters + ; HL = Pointer to the original block + ; BC = New Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; +; Notes: + ; If BC = 0, the block is freed, otherwise + ; the content of the original block is copied to the new one, and + ; the new size is adjusted. If BC < original length, the content + ; will be truncated. Otherwise, extra block content might contain + ; memory garbage. + ; + ; --------------------------------------------------------------------- +__REALLOC: ; Reallocates block pointed by HL, with new length BC + PROC + + LOCAL __REALLOC_END + + ld a, h + or l + jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc + + ld e, (hl) + inc hl + ld d, (hl) ; DE = First 2 bytes of HL block + + push hl + exx + pop de + inc de ; DE' <- HL + 2 + exx ; DE' <- HL (Saves current pointer into DE') + + dec hl ; HL = Block start + + push de + push bc + call __MEM_FREE ; Frees current block + pop bc + push bc + call __MEM_ALLOC ; Gets a new block of length BC + pop bc + pop de + + ld a, h + or l + ret z ; Return if HL == NULL (No memory) + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Recovers first 2 bytes in HL + + dec bc + dec bc ; BC = BC - 2 (Two bytes copied) + + ld a, b + or c + jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) + + exx + push de + exx + pop de ; DE <- DE' ; Start of remaining block + + push hl ; Saves current Block + 2 start + ex de, hl ; Exchanges them: DE is destiny block + ldir ; Copies BC Bytes + pop hl ; Recovers Block + 2 start + +__REALLOC_END: + + dec hl ; Set HL + dec hl ; To begin of block + ret + + ENDP + +#line 2 "strcpy.asm" + + ; String library + + +__STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) + PROC + + LOCAL __STRREALLOC + LOCAL __STRCONTINUE + LOCAL __B_IS_NULL + LOCAL __NOTHING_TO_COPY + + ld b, d + ld c, e + ld a, b + or c + jr z, __B_IS_NULL + + ex de, hl + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(b$) + ex de, hl ; DE = &b$ + +__B_IS_NULL: ; Jumps here if B$ pointer is NULL + inc bc + inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) + + push de + push hl + + ld a, h + or l + jr z, __STRREALLOC + + dec hl + ld d, (hl) + dec hl + ld e, (hl) ; DE = MEMBLOCKSIZE(a$) + dec de + dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) + + ld h, b + ld l, c ; HL = LEN(b$) + 2 => Minimum block size required + ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 + + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) + sbc hl, de ; Carry if len(b$) > Blocklen(a$) + jr c, __STRREALLOC ; No need to realloc + ; Need to reallocate at least to len(b$) + 2 + ex de, hl ; DE = Remaining bytes in a$ mem block. + ld hl, 4 + sbc hl, de ; if remaining bytes < 4 we can continue + jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes + +__STRREALLOC: + pop hl + call __REALLOC ; Returns in HL a new pointer with BC bytes allocated + push hl + +__STRCONTINUE: ; Pops hl and de SWAPPED + pop de ; DE = &a$ + pop hl ; HL = &b$ + + ld a, d ; Return if not enough memory for new length + or e + ret z ; Return if DE == NULL (0) + +__STRCPY: ; Copies string pointed by HL into string pointed by DE + ; Returns DE as HL (new pointer) + ld a, h + or l + jr z, __NOTHING_TO_COPY + ld c, (hl) + inc hl + ld b, (hl) + dec hl + inc bc + inc bc + push de + ldir + pop hl + ret + +__NOTHING_TO_COPY: + ex de, hl + ld (hl), e + inc hl + ld (hl), d + dec hl + ret + + ENDP + +#line 14 "storestr.asm" + +__PISTORE_STR: ; Indirect assignement at (IX + BC) + push ix + pop hl + add hl, bc + +__ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + +__STORE_STR: + push de ; Pointer to b$ + push hl ; Array pointer to variable memory address + + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation + ex de, hl ; DE = new address of a$ + pop hl ; Recover variable memory address pointer + + ld (hl), e + inc hl + ld (hl), d ; Stores a$ ptr into elemem ptr + + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) + ret + +#line 64 "let_array_substr5.bas" + +ZXBASIC_USER_DATA: +_b: + DEFB 03h + DEFB 00h +_a: + DEFW 0000h + DEFB 02h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/let_array_substr5.bas b/tests/functional/let_array_substr5.bas new file mode 100644 index 000000000..9f18b698f --- /dev/null +++ b/tests/functional/let_array_substr5.bas @@ -0,0 +1,5 @@ +DIM a$(10) +DIM b as UInteger = 3 +LET a$(b) = "0123456789" +a$(b)(1) = "HELLO" + diff --git a/tests/functional/let_array_substr6.bas b/tests/functional/let_array_substr6.bas new file mode 100644 index 000000000..f0b849197 --- /dev/null +++ b/tests/functional/let_array_substr6.bas @@ -0,0 +1,3 @@ +DIM a(10) as UInteger +LET a(3)(5) = 4 + diff --git a/tests/functional/let_array_substr7.asm b/tests/functional/let_array_substr7.asm new file mode 100644 index 000000000..a9d9b8ba7 --- /dev/null +++ b/tests/functional/let_array_substr7.asm @@ -0,0 +1,1155 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld de, __LABEL0 + ld hl, _a + 9 + call __STORE_STR + ld hl, __LABEL1 + call __LOADSTR + push hl + xor a + push af + ld hl, 1 + push hl + ld hl, 1 + push hl + ld hl, (_a + 9) + call __LETSUBSTR + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__LABEL0: + DEFW 000Ah + DEFB 30h + DEFB 31h + DEFB 32h + DEFB 33h + DEFB 34h + DEFB 35h + DEFB 36h + DEFB 37h + DEFB 38h + DEFB 39h +__LABEL1: + DEFW 0005h + DEFB 48h + DEFB 45h + DEFB 4Ch + DEFB 4Ch + DEFB 4Fh +#line 1 "letsubstr.asm" + + ; Substring assigment eg. LET a$(p0 TO p1) = "xxxx" + ; HL = Start of string + ; TOP of the stack -> p1 (16 bit, unsigned) + ; TOP -1 of the stack -> p0 register + ; TOP -2 Flag (popped out in A register) + ; A Register => 0 if HL is not freed from memory + ; => Not 0 if HL must be freed from memory on exit + ; TOP -3 B$ address + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 11 "letsubstr.asm" + +__LETSUBSTR: + PROC + + LOCAL __CONT0 + LOCAL __CONT1 + LOCAL __CONT2 + LOCAL __FREE_STR + LOCAL __FREE_STR0 + + exx + pop hl ; Return address + pop de ; p1 + pop bc ; p0 + exx + + pop af ; Flag + ex af, af' ; Save it for later + + pop de ; B$ + + exx + push hl ; push ret addr back + exx + + ld a, h + or l + jp z, __FREE_STR0 ; Return if null + + ld c, (hl) + inc hl + ld b, (hl) ; BC = Str length + inc hl ; HL = String start + push bc + + exx + ex de, hl + or a + sbc hl, bc ; HL = Length of string requester by user + inc hl ; len (a$(p0 TO p1)) = p1 - p0 + 1 + ex de, hl ; Saves it in DE + + pop hl ; HL = String length + exx + jp c, __FREE_STR0 ; Return if greather + exx ; Return if p0 > p1 + + or a + sbc hl, bc ; P0 >= String length? + exx + + jp z, __FREE_STR0 ; Return if equal + jp c, __FREE_STR0 ; Return if greather + + exx + add hl, bc ; Add it back + + sbc hl, de ; Length of substring > string => Truncate it + add hl, de ; add it back + jr nc, __CONT0 ; Length of substring within a$ + + ld d, h + ld e, l ; Truncate length of substring to fit within the strlen + +__CONT0: ; At this point DE = Length of subtring to copy + ; BC = start of char to copy + push de + + push bc + exx + pop bc + + add hl, bc ; Start address (within a$) so copy from b$ (in DE) + + push hl + exx + pop hl ; Start address (within a$) so copy from b$ (in DE) + + ld b, d ; Length of string + ld c, e + + ld (hl), ' ' + ld d, h + ld e, l + inc de + dec bc + ld a, b + or c + jr z, __CONT2 + + ; At this point HL = DE = Start of Write zone in a$ + ; BC = Number of chars to write + + ldir + +__CONT2: + + pop bc ; Recovers Length of string to copy + exx + ex de, hl ; HL = Source, DE = Target + + ld a, h + or l + jp z, __FREE_STR ; Return if B$ is NULL + + ld c, (hl) + inc hl + ld b, (hl) + inc hl + + ld a, b + or c + jp z, __FREE_STR ; Return if len(b$) = 0 + + ; Now if len(b$) < len(char to copy), copy only len(b$) chars + + push de + push hl + push bc + exx + pop hl ; LEN (b$) + or a + sbc hl, bc + add hl, bc + jr nc, __CONT1 + + ; If len(b$) < len(to copy) + ld b, h ; BC = len(to copy) + ld c, l + +__CONT1: + pop hl + pop de + ldir ; Copy b$ into a$(x to y) + + exx + ex de, hl + +__FREE_STR0: + ex de, hl + +__FREE_STR: + ex af, af' + or a ; If not 0, free + jp nz, __MEM_FREE + ret + + ENDP + +#line 51 "let_array_substr7.bas" +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 69 "alloc.asm" + + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 52 "let_array_substr7.bas" +#line 1 "storestr.asm" + +; vim:ts=4:et:sw=4 + ; Stores value of current string pointed by DE register into address pointed by HL + ; Returns DE = Address pointer (&a$) + ; Returns HL = HL (b$ => might be needed later to free it from the heap) + ; + ; e.g. => HL = _variableName (DIM _variableName$) + ; DE = Address into the HEAP + ; + ; This function will resize (REALLOC) the space pointed by HL + ; before copying the content of b$ into a$ + + +#line 1 "strcpy.asm" + +#line 1 "realloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + + + + ; --------------------------------------------------------------------- + ; MEM_REALLOC + ; Reallocates a block of memory in the heap. + ; + ; Parameters + ; HL = Pointer to the original block + ; BC = New Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; +; Notes: + ; If BC = 0, the block is freed, otherwise + ; the content of the original block is copied to the new one, and + ; the new size is adjusted. If BC < original length, the content + ; will be truncated. Otherwise, extra block content might contain + ; memory garbage. + ; + ; --------------------------------------------------------------------- +__REALLOC: ; Reallocates block pointed by HL, with new length BC + PROC + + LOCAL __REALLOC_END + + ld a, h + or l + jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc + + ld e, (hl) + inc hl + ld d, (hl) ; DE = First 2 bytes of HL block + + push hl + exx + pop de + inc de ; DE' <- HL + 2 + exx ; DE' <- HL (Saves current pointer into DE') + + dec hl ; HL = Block start + + push de + push bc + call __MEM_FREE ; Frees current block + pop bc + push bc + call __MEM_ALLOC ; Gets a new block of length BC + pop bc + pop de + + ld a, h + or l + ret z ; Return if HL == NULL (No memory) + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Recovers first 2 bytes in HL + + dec bc + dec bc ; BC = BC - 2 (Two bytes copied) + + ld a, b + or c + jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) + + exx + push de + exx + pop de ; DE <- DE' ; Start of remaining block + + push hl ; Saves current Block + 2 start + ex de, hl ; Exchanges them: DE is destiny block + ldir ; Copies BC Bytes + pop hl ; Recovers Block + 2 start + +__REALLOC_END: + + dec hl ; Set HL + dec hl ; To begin of block + ret + + ENDP + +#line 2 "strcpy.asm" + + ; String library + + +__STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) + PROC + + LOCAL __STRREALLOC + LOCAL __STRCONTINUE + LOCAL __B_IS_NULL + LOCAL __NOTHING_TO_COPY + + ld b, d + ld c, e + ld a, b + or c + jr z, __B_IS_NULL + + ex de, hl + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(b$) + ex de, hl ; DE = &b$ + +__B_IS_NULL: ; Jumps here if B$ pointer is NULL + inc bc + inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) + + push de + push hl + + ld a, h + or l + jr z, __STRREALLOC + + dec hl + ld d, (hl) + dec hl + ld e, (hl) ; DE = MEMBLOCKSIZE(a$) + dec de + dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) + + ld h, b + ld l, c ; HL = LEN(b$) + 2 => Minimum block size required + ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 + + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) + sbc hl, de ; Carry if len(b$) > Blocklen(a$) + jr c, __STRREALLOC ; No need to realloc + ; Need to reallocate at least to len(b$) + 2 + ex de, hl ; DE = Remaining bytes in a$ mem block. + ld hl, 4 + sbc hl, de ; if remaining bytes < 4 we can continue + jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes + +__STRREALLOC: + pop hl + call __REALLOC ; Returns in HL a new pointer with BC bytes allocated + push hl + +__STRCONTINUE: ; Pops hl and de SWAPPED + pop de ; DE = &a$ + pop hl ; HL = &b$ + + ld a, d ; Return if not enough memory for new length + or e + ret z ; Return if DE == NULL (0) + +__STRCPY: ; Copies string pointed by HL into string pointed by DE + ; Returns DE as HL (new pointer) + ld a, h + or l + jr z, __NOTHING_TO_COPY + ld c, (hl) + inc hl + ld b, (hl) + dec hl + inc bc + inc bc + push de + ldir + pop hl + ret + +__NOTHING_TO_COPY: + ex de, hl + ld (hl), e + inc hl + ld (hl), d + dec hl + ret + + ENDP + +#line 14 "storestr.asm" + +__PISTORE_STR: ; Indirect assignement at (IX + BC) + push ix + pop hl + add hl, bc + +__ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + +__STORE_STR: + push de ; Pointer to b$ + push hl ; Array pointer to variable memory address + + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation + ex de, hl ; DE = new address of a$ + pop hl ; Recover variable memory address pointer + + ld (hl), e + inc hl + ld (hl), d ; Stores a$ ptr into elemem ptr + + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) + ret + +#line 53 "let_array_substr7.bas" + +ZXBASIC_USER_DATA: +_a: + DEFW 0000h + DEFB 02h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/let_array_substr7.bas b/tests/functional/let_array_substr7.bas new file mode 100644 index 000000000..2f800a0e2 --- /dev/null +++ b/tests/functional/let_array_substr7.bas @@ -0,0 +1,4 @@ +DIM a$(10) +LET a$(3) = "0123456789" +a$(3)(1) = "HELLO" + diff --git a/tests/functional/let_array_substr8.bas b/tests/functional/let_array_substr8.bas new file mode 100644 index 000000000..6a9a48047 --- /dev/null +++ b/tests/functional/let_array_substr8.bas @@ -0,0 +1,5 @@ +DIM a$(10) +LET a(3) = "0123456789" +LET a(3, 4)(1) = "HELLO" +print a$(3) + diff --git a/tests/functional/let_array_substr9.asm b/tests/functional/let_array_substr9.asm new file mode 100644 index 000000000..0f5de0dba --- /dev/null +++ b/tests/functional/let_array_substr9.asm @@ -0,0 +1,1155 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld de, __LABEL0 + ld hl, _a + 9 + call __STORE_STR + ld hl, __LABEL1 + call __LOADSTR + push hl + xor a + push af + ld hl, 1 + push hl + ld hl, 65534 + push hl + ld hl, (_a + 9) + call __LETSUBSTR + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__LABEL0: + DEFW 000Ah + DEFB 30h + DEFB 31h + DEFB 32h + DEFB 33h + DEFB 34h + DEFB 35h + DEFB 36h + DEFB 37h + DEFB 38h + DEFB 39h +__LABEL1: + DEFW 0005h + DEFB 48h + DEFB 45h + DEFB 4Ch + DEFB 4Ch + DEFB 4Fh +#line 1 "letsubstr.asm" + + ; Substring assigment eg. LET a$(p0 TO p1) = "xxxx" + ; HL = Start of string + ; TOP of the stack -> p1 (16 bit, unsigned) + ; TOP -1 of the stack -> p0 register + ; TOP -2 Flag (popped out in A register) + ; A Register => 0 if HL is not freed from memory + ; => Not 0 if HL must be freed from memory on exit + ; TOP -3 B$ address + +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 69 "free.asm" + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 11 "letsubstr.asm" + +__LETSUBSTR: + PROC + + LOCAL __CONT0 + LOCAL __CONT1 + LOCAL __CONT2 + LOCAL __FREE_STR + LOCAL __FREE_STR0 + + exx + pop hl ; Return address + pop de ; p1 + pop bc ; p0 + exx + + pop af ; Flag + ex af, af' ; Save it for later + + pop de ; B$ + + exx + push hl ; push ret addr back + exx + + ld a, h + or l + jp z, __FREE_STR0 ; Return if null + + ld c, (hl) + inc hl + ld b, (hl) ; BC = Str length + inc hl ; HL = String start + push bc + + exx + ex de, hl + or a + sbc hl, bc ; HL = Length of string requester by user + inc hl ; len (a$(p0 TO p1)) = p1 - p0 + 1 + ex de, hl ; Saves it in DE + + pop hl ; HL = String length + exx + jp c, __FREE_STR0 ; Return if greather + exx ; Return if p0 > p1 + + or a + sbc hl, bc ; P0 >= String length? + exx + + jp z, __FREE_STR0 ; Return if equal + jp c, __FREE_STR0 ; Return if greather + + exx + add hl, bc ; Add it back + + sbc hl, de ; Length of substring > string => Truncate it + add hl, de ; add it back + jr nc, __CONT0 ; Length of substring within a$ + + ld d, h + ld e, l ; Truncate length of substring to fit within the strlen + +__CONT0: ; At this point DE = Length of subtring to copy + ; BC = start of char to copy + push de + + push bc + exx + pop bc + + add hl, bc ; Start address (within a$) so copy from b$ (in DE) + + push hl + exx + pop hl ; Start address (within a$) so copy from b$ (in DE) + + ld b, d ; Length of string + ld c, e + + ld (hl), ' ' + ld d, h + ld e, l + inc de + dec bc + ld a, b + or c + jr z, __CONT2 + + ; At this point HL = DE = Start of Write zone in a$ + ; BC = Number of chars to write + + ldir + +__CONT2: + + pop bc ; Recovers Length of string to copy + exx + ex de, hl ; HL = Source, DE = Target + + ld a, h + or l + jp z, __FREE_STR ; Return if B$ is NULL + + ld c, (hl) + inc hl + ld b, (hl) + inc hl + + ld a, b + or c + jp z, __FREE_STR ; Return if len(b$) = 0 + + ; Now if len(b$) < len(char to copy), copy only len(b$) chars + + push de + push hl + push bc + exx + pop hl ; LEN (b$) + or a + sbc hl, bc + add hl, bc + jr nc, __CONT1 + + ; If len(b$) < len(to copy) + ld b, h ; BC = len(to copy) + ld c, l + +__CONT1: + pop hl + pop de + ldir ; Copy b$ into a$(x to y) + + exx + ex de, hl + +__FREE_STR0: + ex de, hl + +__FREE_STR: + ex af, af' + or a ; If not 0, free + jp nz, __MEM_FREE + ret + + ENDP + +#line 51 "let_array_substr9.bas" +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 69 "alloc.asm" + + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 52 "let_array_substr9.bas" +#line 1 "storestr.asm" + +; vim:ts=4:et:sw=4 + ; Stores value of current string pointed by DE register into address pointed by HL + ; Returns DE = Address pointer (&a$) + ; Returns HL = HL (b$ => might be needed later to free it from the heap) + ; + ; e.g. => HL = _variableName (DIM _variableName$) + ; DE = Address into the HEAP + ; + ; This function will resize (REALLOC) the space pointed by HL + ; before copying the content of b$ into a$ + + +#line 1 "strcpy.asm" + +#line 1 "realloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + + + + ; --------------------------------------------------------------------- + ; MEM_REALLOC + ; Reallocates a block of memory in the heap. + ; + ; Parameters + ; HL = Pointer to the original block + ; BC = New Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; +; Notes: + ; If BC = 0, the block is freed, otherwise + ; the content of the original block is copied to the new one, and + ; the new size is adjusted. If BC < original length, the content + ; will be truncated. Otherwise, extra block content might contain + ; memory garbage. + ; + ; --------------------------------------------------------------------- +__REALLOC: ; Reallocates block pointed by HL, with new length BC + PROC + + LOCAL __REALLOC_END + + ld a, h + or l + jp z, __MEM_ALLOC ; If HL == NULL, just do a malloc + + ld e, (hl) + inc hl + ld d, (hl) ; DE = First 2 bytes of HL block + + push hl + exx + pop de + inc de ; DE' <- HL + 2 + exx ; DE' <- HL (Saves current pointer into DE') + + dec hl ; HL = Block start + + push de + push bc + call __MEM_FREE ; Frees current block + pop bc + push bc + call __MEM_ALLOC ; Gets a new block of length BC + pop bc + pop de + + ld a, h + or l + ret z ; Return if HL == NULL (No memory) + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Recovers first 2 bytes in HL + + dec bc + dec bc ; BC = BC - 2 (Two bytes copied) + + ld a, b + or c + jp z, __REALLOC_END ; Ret if nothing to copy (BC == 0) + + exx + push de + exx + pop de ; DE <- DE' ; Start of remaining block + + push hl ; Saves current Block + 2 start + ex de, hl ; Exchanges them: DE is destiny block + ldir ; Copies BC Bytes + pop hl ; Recovers Block + 2 start + +__REALLOC_END: + + dec hl ; Set HL + dec hl ; To begin of block + ret + + ENDP + +#line 2 "strcpy.asm" + + ; String library + + +__STRASSIGN: ; Performs a$ = b$ (HL = address of a$; DE = Address of b$) + PROC + + LOCAL __STRREALLOC + LOCAL __STRCONTINUE + LOCAL __B_IS_NULL + LOCAL __NOTHING_TO_COPY + + ld b, d + ld c, e + ld a, b + or c + jr z, __B_IS_NULL + + ex de, hl + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(b$) + ex de, hl ; DE = &b$ + +__B_IS_NULL: ; Jumps here if B$ pointer is NULL + inc bc + inc bc ; BC = BC + 2 ; (LEN(b$) + 2 bytes for storing length) + + push de + push hl + + ld a, h + or l + jr z, __STRREALLOC + + dec hl + ld d, (hl) + dec hl + ld e, (hl) ; DE = MEMBLOCKSIZE(a$) + dec de + dec de ; DE = DE - 2 ; (Membloksize takes 2 bytes for memblock length) + + ld h, b + ld l, c ; HL = LEN(b$) + 2 => Minimum block size required + ex de, hl ; Now HL = BLOCKSIZE(a$), DE = LEN(b$) + 2 + + or a ; Prepare to subtract BLOCKSIZE(a$) - LEN(b$) + sbc hl, de ; Carry if len(b$) > Blocklen(a$) + jr c, __STRREALLOC ; No need to realloc + ; Need to reallocate at least to len(b$) + 2 + ex de, hl ; DE = Remaining bytes in a$ mem block. + ld hl, 4 + sbc hl, de ; if remaining bytes < 4 we can continue + jr nc,__STRCONTINUE ; Otherwise, we realloc, to free some bytes + +__STRREALLOC: + pop hl + call __REALLOC ; Returns in HL a new pointer with BC bytes allocated + push hl + +__STRCONTINUE: ; Pops hl and de SWAPPED + pop de ; DE = &a$ + pop hl ; HL = &b$ + + ld a, d ; Return if not enough memory for new length + or e + ret z ; Return if DE == NULL (0) + +__STRCPY: ; Copies string pointed by HL into string pointed by DE + ; Returns DE as HL (new pointer) + ld a, h + or l + jr z, __NOTHING_TO_COPY + ld c, (hl) + inc hl + ld b, (hl) + dec hl + inc bc + inc bc + push de + ldir + pop hl + ret + +__NOTHING_TO_COPY: + ex de, hl + ld (hl), e + inc hl + ld (hl), d + dec hl + ret + + ENDP + +#line 14 "storestr.asm" + +__PISTORE_STR: ; Indirect assignement at (IX + BC) + push ix + pop hl + add hl, bc + +__ISTORE_STR: ; Indirect assignement, hl point to a pointer to a pointer to the heap! + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + +__STORE_STR: + push de ; Pointer to b$ + push hl ; Array pointer to variable memory address + + ld c, (hl) + inc hl + ld h, (hl) + ld l, c ; HL = (HL) + + call __STRASSIGN ; HL (a$) = DE (b$); HL changed to a new dynamic memory allocation + ex de, hl ; DE = new address of a$ + pop hl ; Recover variable memory address pointer + + ld (hl), e + inc hl + ld (hl), d ; Stores a$ ptr into elemem ptr + + pop hl ; Returns ptr to b$ in HL (Caller might needed to free it from memory) + ret + +#line 53 "let_array_substr9.bas" + +ZXBASIC_USER_DATA: +_a: + DEFW 0000h + DEFB 02h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/let_array_substr9.bas b/tests/functional/let_array_substr9.bas new file mode 100644 index 000000000..a49f31756 --- /dev/null +++ b/tests/functional/let_array_substr9.bas @@ -0,0 +1,4 @@ +DIM a$(10) +LET a(3) = "0123456789" +LET a(3, 1 TO) = "HELLO" + diff --git a/tests/functional/let_array_wrong_dims.bas b/tests/functional/let_array_wrong_dims.bas new file mode 100644 index 000000000..1c1a03d7a --- /dev/null +++ b/tests/functional/let_array_wrong_dims.bas @@ -0,0 +1,3 @@ +DIM a(10) as Byte +LET a(1, 2) = 0 + diff --git a/tests/functional/test_errmsg.txt b/tests/functional/test_errmsg.txt index 9af4012b8..680ae2c14 100644 --- a/tests/functional/test_errmsg.txt +++ b/tests/functional/test_errmsg.txt @@ -121,4 +121,12 @@ substr_expr_err.bas:3: Expected a string type expression. Got byte type instead dup_func_decl.bas:5: duplicated declaration for function 'f' >>> process_file('def_func_inline.bas') def_func_inline.bas:2: Syntax Error. Unexpected token 'END' +>>> process_file('let_array_substr4.bas') +let_array_substr4.bas:2: Array 'a' is not of type String +>>> process_file('let_array_substr6.bas') +let_array_substr6.bas:2: Array 'a' is not of type String +>>> process_file('let_array_substr8.bas') +let_array_substr8.bas:3: Array 'a' has 1 dimensions, not 2 +>>> process_file('let_array_wrong_dims.bas') +let_array_wrong_dims.bas:2: Array 'a' has 1 dimensions, not 2 diff --git a/zxbparser.py b/zxbparser.py index 8ed3aeb71..0cfc9c055 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -296,6 +296,37 @@ def make_array_access(id_, lineno, arglist): return symbols.ARRAYACCESS.make_node(id_, arglist, lineno) +def make_array_substr_assign(lineno, id_, arg_list, substr, expr_): + if arg_list is None or substr is None or expr_ is None: + return None # There were errors + + entry = SYMBOL_TABLE.access_call(id_, lineno) + if entry is None: + return None # There were errors + + if entry.type_ != TYPE.string: + syntax_error(lineno, "Array '%s' is not of type String" % id_) + return None # There were errors + + arr = make_array_access(id_, lineno, arg_list) + if arr is None: + return None # There were errors + + expr_ = make_typecast(arr.type_, expr_, lineno) + if expr_ is None: + return None # There were errors + + s0 = make_typecast(TYPE.uinteger, substr[0], lineno) + if s0 is None: + return None # There were errors + + s1 = make_typecast(TYPE.uinteger, substr[1], lineno) + if s1 is None: + return None # There were errors + + return make_sentence('LETARRAYSUBSTR', arr, s0, s1, expr_) + + def make_call(id_, lineno, args): """ This will return an AST node for a function call/array access. @@ -1033,22 +1064,34 @@ def p_arr_assignment(p): """ statement : ARRAY_ID arg_list EQ expr | LET ARRAY_ID arg_list EQ expr """ - q = p[1:] - i = 2 - if q[0].upper() == 'LET': - q = q[1:] - i = 3 + i = 2 if p[1].upper() == 'LET' else 1 + id_ = p[i] + arg_list = p[i + 1] + expr = p[i + 3] - if q[1] is None or q[3] is None: + p[0] = None + if arg_list is None or expr is None: return # There were errors - p[0] = None - entry = SYMBOL_TABLE.access_call(q[0], p.lineno(i - 1)) + entry = SYMBOL_TABLE.access_call(id_, p.lineno(i)) + if entry is None: + return + + if entry.type_ == TYPE.string: + variable = gl.SYMBOL_TABLE.access_array(id_, p.lineno(i)) + if len(variable.bounds) + 1 == len(arg_list): + ss = arg_list.children.pop().value + p[0] = make_array_substr_assign(p.lineno(i), id_, arg_list, (ss, ss), expr) + return + + arr = make_array_access(id_, p.lineno(i), arg_list) + if arr is None: + return + + expr = make_typecast(arr.type_, expr, p.lineno(i)) if entry is None: return - arr = make_array_access(q[0], p.lineno(i), q[1]) - expr = make_typecast(arr.type_, q[3], p.lineno(i)) p[0] = make_sentence('LETARRAY', arr, expr) @@ -2537,6 +2580,87 @@ def p_arr_access_expr(p): entry.accessed = True +def p_let_arr_substr(p): + """ statement : LET ARRAY_ID arg_list substr EQ expr + | ARRAY_ID arg_list substr EQ expr + """ + i = 2 if p[1].upper() == 'LET' else 1 + + id_ = p[i] + arg_list = p[i + 1] + substr = p[i + 2] + expr_ = p[i + 4] + p[0] = make_array_substr_assign(p.lineno(i), id_, arg_list, substr, expr_) + + +def p_let_arr_substr_single(p): + """ statement : LET ARRAY_ID arg_list LP expr RP EQ expr + | ARRAY_ID arg_list LP expr RP EQ expr + """ + i = 2 if p[1].upper() == 'LET' else 1 + + id_ = p[i] + arg_list = p[i + 1] + substr = (p[i + 3], p[i + 3]) + expr_ = p[i + 6] + p[0] = make_array_substr_assign(p.lineno(i), id_, arg_list, substr, expr_) + + +def p_let_arr_substr_in_args(p): + """ statement : LET ARRAY_ID LP arguments TO RP EQ expr + | ARRAY_ID LP arguments TO RP EQ expr + """ + i = 2 if p[1].upper() == 'LET' else 1 + + id_ = p[i] + arg_list = p[i + 2] + substr = (arg_list.children.pop().value, + make_number(gl.MAX_STRSLICE_IDX, lineno=p.lineno(i + 3))) + expr_ = p[i + 6] + p[0] = make_array_substr_assign(p.lineno(i), id_, arg_list, substr, expr_) + + +def p_let_arr_substr_in_args2(p): + """ statement : LET ARRAY_ID LP arguments COMMA TO expr RP EQ expr + | ARRAY_ID LP arguments COMMA TO expr RP EQ expr + """ + i = 2 if p[1].upper() == 'LET' else 1 + + id_ = p[i] + arg_list = p[i + 2] + top_ = p[i + 5] + substr = (make_number(0, lineno=p.lineno(i + 4)), top_) + expr_ = p[i + 8] + p[0] = make_array_substr_assign(p.lineno(i), id_, arg_list, substr, expr_) + + +def p_let_arr_substr_in_args3(p): + """ statement : LET ARRAY_ID LP arguments COMMA TO RP EQ expr + | ARRAY_ID LP arguments COMMA TO RP EQ expr + """ + i = 2 if p[1].upper() == 'LET' else 1 + + id_ = p[i] + arg_list = p[i + 2] + substr = (make_number(0, lineno=p.lineno(i + 4)), + make_number(gl.MAX_STRSLICE_IDX, lineno=p.lineno(i + 3))) + expr_ = p[i + 7] + p[0] = make_array_substr_assign(p.lineno(i), id_, arg_list, substr, expr_) + + +def p_let_arr_substr_in_args4(p): + """ statement : LET ARRAY_ID LP arguments TO expr RP EQ expr + | ARRAY_ID LP arguments TO expr RP EQ expr + """ + i = 2 if p[1].upper() == 'LET' else 1 + + id_ = p[i] + arg_list = p[i + 2] + substr = (arg_list.children.pop().value, p[i + 4]) + expr_ = p[i + 7] + p[0] = make_array_substr_assign(p.lineno(i), id_, arg_list, substr, expr_) + + def p_addr_of_array_element(p): """ bexpr : ADDRESSOF ARRAY_ID arg_list """ From 3d7609cde6b9c0812845b5c0937374598b3e006b Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 9 Apr 2018 10:37:41 +0200 Subject: [PATCH 205/247] chore: add input example --- examples/inputexample.bas | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 examples/inputexample.bas diff --git a/examples/inputexample.bas b/examples/inputexample.bas new file mode 100644 index 000000000..977098bcf --- /dev/null +++ b/examples/inputexample.bas @@ -0,0 +1,7 @@ +#include + +print at 10, 5; "Type something: "; +a$ = input(20) +print +print "You typed: "; a$ + From 95eba7fe95f49f273292089e3b280af181b910ec Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 9 Apr 2018 11:21:23 +0200 Subject: [PATCH 206/247] chore: ignore some files for lang detection This is (mostly) a Python project. Set this so GitHub correctly detects it, and not as an asm project. --- .gitattributes | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitattributes b/.gitattributes index fa1d1c12f..2e0a155c0 100644 --- a/.gitattributes +++ b/.gitattributes @@ -13,3 +13,6 @@ *.png binary +*.bas linguist-vendored +*.asm linguist-vendored + From 80a4b3d8a8ee4c4680b48860dd9efe85c3c6f55d Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 10 Apr 2018 10:08:49 +0200 Subject: [PATCH 207/247] =?UTF-8?q?Bump=20version:=201.8.2=20=E2=86=92=201?= =?UTF-8?q?.8.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- ChangeLog | 8 ++++++++ version.py | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 7c4aa7312..46d8a63ec 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,4 +1,4 @@ [bumpversion] -current_version = 1.8.2 +current_version = 1.8.3 files = version.py diff --git a/ChangeLog b/ChangeLog index e721053b1..c044b35b0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +================================================================ +Changes from Version 1.8.2 to 1.8.3 +! Bugfix in the peephole optimizer (-O2) +! Several bugfixes to improve stability ++ Optimization in the peephole optimizer (-O1) ++ Support for extended array str element operations +! Other syntax bugfixes + ================================================================ Changes from Version 1.8.1 to 1.8.2 ! Bugfixes in the peephole optimizer diff --git a/version.py b/version.py index 7e7369239..32e3f09b9 100755 --- a/version.py +++ b/version.py @@ -1 +1 @@ -VERSION = '1.8.2' +VERSION = '1.8.3' From 1c922ef7bcacab1c6d1937f0b152b1bf81212592 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 15 Apr 2018 11:03:36 +0200 Subject: [PATCH 208/247] bugfix: bug in peephole -O3 crash Fixes two bugs (crash and wrong optimization) that might happen under some circumstances with -O3 in case OPT7 --- arch/zx48k/optimizer.py | 22 ++- tests/functional/opt3_OPT27wws2.asm | 285 ++++++++++++++++++++++++++++ tests/functional/opt3_OPT27wws2.bas | 5 + 3 files changed, 308 insertions(+), 4 deletions(-) create mode 100644 tests/functional/opt3_OPT27wws2.asm create mode 100644 tests/functional/opt3_OPT27wws2.bas diff --git a/arch/zx48k/optimizer.py b/arch/zx48k/optimizer.py index 98bd41f02..8beedb11a 100644 --- a/arch/zx48k/optimizer.py +++ b/arch/zx48k/optimizer.py @@ -905,6 +905,12 @@ def __set_asm(self, value): asm = property(__get_asm, __set_asm) + def __str__(self): + return self.asm + + def __repr__(self): + return '{0}:{1}'.format(self.addr, str(self)) + @property def is_label(self): """ Returns whether the current addr @@ -1684,9 +1690,14 @@ def optimize(self): continue for i in range(len(self)): - if self.mem[i].is_label: - # ignore labels - continue + try: + if self.mem[i].is_label: + # ignore labels + continue + except IndexError: + print(i) + print('\n'.join(str(x) for x in self.mem)) + raise i1 = self.mem[i].inst o1 = self.mem[i].opers @@ -2017,8 +2028,11 @@ def optimize(self): if OPT27 and i1 in ('cp', 'or', 'and', 'add', 'adc', 'sub', 'sbc') and o1[-1] != 'a' and \ not self.is_used(o1[-1], i + 1) and i0 == 'ld' and o0[0] == o1[-1] and \ (o0[1] == '(hl)' or RE_IXIND.match(o0[1])): - self[i] = '{0} {1}'.format(i1, o0[1]) + template = '{0} %s{1}' % ('a, ' if i1 in ('add', 'adc', 'sbc') else '') + self[i] = template.format(i1, o0[1]) self.pop(i - 1) + changed = True + break regs.op(i1, o1) diff --git a/tests/functional/opt3_OPT27wws2.asm b/tests/functional/opt3_OPT27wws2.asm new file mode 100644 index 000000000..f1eea3a4a --- /dev/null +++ b/tests/functional/opt3_OPT27wws2.asm @@ -0,0 +1,285 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, (_n) + push hl + ld hl, _yenem + call __ARRAY + ld a, (hl) + push af + ld hl, (_n) + push hl + ld hl, _incyenem + call __ARRAY + pop af + add a, (hl) + push af + ld hl, (_n) + push hl + ld hl, _yenem + call __ARRAY + pop af + ld (hl), a + ld bc, 0 +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + pop iy + pop ix + exx + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "array.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; ------------------------------------------------------------------- + ; Simple array Index routine + ; Number of total indexes dimensions - 1 at beginning of memory + ; HL = Start of array memory (First two bytes contains N-1 dimensions) + ; Dimension values on the stack, (top of the stack, highest dimension) + ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> + + ; For any array of N dimension A(aN-1, ..., a1, a0) + ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as + ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] +; What I will do here is to calculate the following sequence: + ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... + + +#line 1 "mul16.asm" + +__MUL16: ; Mutiplies HL with the last value stored into de stack + ; Works for both signed and unsigned + + PROC + + LOCAL __MUL16LOOP + LOCAL __MUL16NOADD + + ex de, hl + pop hl ; Return address + ex (sp), hl ; CALLEE caller convention + +;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand + ;; ld c, h + ;; ld a, l ; C,A => 1st Operand + ;; + ;; ld hl, 0 ; Accumulator + ;; ld b, 16 + ;; +;;__MUL16LOOP: + ;; sra c ; C,A >> 1 (Arithmetic) + ;; rra + ;; + ;; jr nc, __MUL16NOADD + ;; add hl, de + ;; +;;__MUL16NOADD: + ;; sla e + ;; rl d + ;; + ;; djnz __MUL16LOOP + +__MUL16_FAST: + ld b, 16 + ld a, d + ld c, e + ex de, hl + ld hl, 0 + +__MUL16LOOP: + add hl, hl ; hl << 1 + sla c + rla ; a,c << 1 + jp nc, __MUL16NOADD + add hl, de + +__MUL16NOADD: + djnz __MUL16LOOP + + ret ; Result in hl (16 lower bits) + + ENDP + +#line 20 "array.asm" + +#line 24 "/src/zxb/trunk/library-asm/array.asm" + +__ARRAY: + PROC + + LOCAL LOOP + LOCAL ARRAY_END + LOCAL RET_ADDRESS ; Stores return address + + ex (sp), hl ; Return address in HL, array address in the stack + ld (RET_ADDRESS + 1), hl ; Stores it for later + + exx + pop hl ; Will use H'L' as the pointer + ld c, (hl) ; Loads Number of dimensions from (hl) + inc hl + ld b, (hl) + inc hl ; Ready + exx + + ld hl, 0 ; BC = Offset "accumulator" + +#line 48 "/src/zxb/trunk/library-asm/array.asm" + +LOOP: + pop bc ; Get next index (Ai) from the stack + +#line 60 "/src/zxb/trunk/library-asm/array.asm" + + add hl, bc ; Adds current index + + exx ; Checks if B'C' = 0 + ld a, b ; Which means we must exit (last element is not multiplied by anything) + or c + jr z, ARRAY_END ; if B'Ci == 0 we are done + + ld e, (hl) ; Loads next dimension into D'E' + inc hl + ld d, (hl) + inc hl + push de + dec bc ; Decrements loop counter + exx + pop de ; DE = Max bound Number (i-th dimension) + +#line 80 "/src/zxb/trunk/library-asm/array.asm" + ;call __MUL16_FAST ; HL *= DE + call __FNMUL +#line 86 "/src/zxb/trunk/library-asm/array.asm" + jp LOOP + +ARRAY_END: + ld e, (hl) + inc hl + ld d, c ; C = 0 => DE = E = Element size + push hl + push de + exx + +#line 100 "/src/zxb/trunk/library-asm/array.asm" + LOCAL ARRAY_SIZE_LOOP + + ex de, hl + ld hl, 0 + pop bc + ld b, c +ARRAY_SIZE_LOOP: + add hl, de + djnz ARRAY_SIZE_LOOP + + ;; Even faster + ;pop bc + + ;ld d, h + ;ld e, l + + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, hl + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, hl + ;dec c + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, de + ;__ARRAY_FIN: +#line 131 "/src/zxb/trunk/library-asm/array.asm" + + pop de + add hl, de ; Adds element start + +RET_ADDRESS: + ld de, 0 + push de + ret ; HL = (Start of Elements + Offset) + + ;; Performs a faster multiply for little 16bit numbs + LOCAL __FNMUL, __FNMUL2 + +__FNMUL: + xor a + or d + jp nz, __MUL16_FAST + + or e + ex de, hl + ret z + + cp 33 + jp nc, __MUL16_FAST + + ld b, l + ld l, h ; HL = 0 + +__FNMUL2: + add hl, de + djnz __FNMUL2 + ret + + ENDP + +#line 35 "opt3_OPT27wws2.bas" + +ZXBASIC_USER_DATA: +_n: + DEFB 00, 00 +_yenem: + DEFW 0000h + DEFB 01h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h +_incyenem: + DEFW 0000h + DEFB 01h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/opt3_OPT27wws2.bas b/tests/functional/opt3_OPT27wws2.bas new file mode 100644 index 000000000..d98318c46 --- /dev/null +++ b/tests/functional/opt3_OPT27wws2.bas @@ -0,0 +1,5 @@ +DIM n as Uinteger +DIM yenem(10) as Byte +DIM incyenem(10) as Byte +yenem(n)=yenem(n)+incyenem(n) + From 681681ca43acd9eb09cce2fc5fe929848ba381a7 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 29 Apr 2018 18:35:03 +0200 Subject: [PATCH 209/247] cleanup: use correct identifiers Use KIND.function and KIND.sub instead of 'function' or 'sub' --- zxbparser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zxbparser.py b/zxbparser.py index 0cfc9c055..ffe664869 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -1943,7 +1943,7 @@ def p_return(p): p[0] = make_sentence('RETURN') return - if FUNCTION_LEVEL[-1].kind != 'sub': + if FUNCTION_LEVEL[-1].kind != KIND.sub: syntax_error(p.lineno(1), 'Syntax Error: Functions must RETURN a value, or use EXIT FUNCTION instead.') p[0] = None return @@ -1963,7 +1963,7 @@ def p_return_expr(p): p[0] = None return - if FUNCTION_LEVEL[-1].kind != 'function': + if FUNCTION_LEVEL[-1].kind != KIND.function: syntax_error(p.lineno(1), 'Syntax Error: SUBs cannot return a value') p[0] = None return From 91743413522dd056a48df1b800ed59006e6d1635 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 29 Apr 2018 18:39:01 +0200 Subject: [PATCH 210/247] bugfix: do not optimize AT variables Vars defined with AT (address) should not be optimized as they might have desired collateral effects. Only normal variables should be optimized. --- tests/functional/opt2_dim_at.asm | 38 ++++++++++++++++++++++++++++++++ tests/functional/opt2_dim_at.bas | 5 +++++ zxbparser.py | 1 + 3 files changed, 44 insertions(+) create mode 100644 tests/functional/opt2_dim_at.asm create mode 100644 tests/functional/opt2_dim_at.bas diff --git a/tests/functional/opt2_dim_at.asm b/tests/functional/opt2_dim_at.asm new file mode 100644 index 000000000..c5d15deae --- /dev/null +++ b/tests/functional/opt2_dim_at.asm @@ -0,0 +1,38 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, 65000 + ld (_UDGptr), hl + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + pop iy + pop ix + exx + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: + _UDGptr EQU 23675 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/opt2_dim_at.bas b/tests/functional/opt2_dim_at.bas new file mode 100644 index 000000000..d16ea846e --- /dev/null +++ b/tests/functional/opt2_dim_at.bas @@ -0,0 +1,5 @@ +REM variables with AT should never be optimized +REM they don't take space and might have collateral (desired) effects +DIM UDGptr As Uinteger AT 23675 +LET UDGptr = 65000 + diff --git a/zxbparser.py b/zxbparser.py index ffe664869..5323a440c 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -653,6 +653,7 @@ def p_var_decl_at(p): return else: entry.addr = str(make_typecast(_TYPE(gl.STR_INDEX_TYPE), p[5], p.lineno(4)).value) + entry.accessed = True if entry.scope == SCOPE.local: SYMBOL_TABLE.make_static(entry.name) From 3e2601744d25d4ab5ab4c3037eb37d7a44ec9e68 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 29 Apr 2018 22:20:51 +0200 Subject: [PATCH 211/247] bugfix: crash on undeclared array --- tests/functional/test_errmsg.txt | 2 ++ zxbparser.py | 3 +++ 2 files changed, 5 insertions(+) diff --git a/tests/functional/test_errmsg.txt b/tests/functional/test_errmsg.txt index 680ae2c14..32ca5daf9 100644 --- a/tests/functional/test_errmsg.txt +++ b/tests/functional/test_errmsg.txt @@ -129,4 +129,6 @@ let_array_substr6.bas:2: Array 'a' is not of type String let_array_substr8.bas:3: Array 'a' has 1 dimensions, not 2 >>> process_file('let_array_wrong_dims.bas') let_array_wrong_dims.bas:2: Array 'a' has 1 dimensions, not 2 +>>> process_file('alxinho1.bas') +alxinho1.bas:3: Undeclared array "a" diff --git a/zxbparser.py b/zxbparser.py index 5323a440c..c2e2a6973 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -668,6 +668,9 @@ def p_var_decl_ini(p): "Initialized variables must be declared one by one.") return + if p[5] is None: + return + if not is_static(p[5]): if isinstance(p[5], symbols.UNARY): p[5] = make_constexpr(p.lineno(4), p[5]) # Delayed constant evaluation From afb76201a9aabc6e0353c5bb01039a58b1b88214 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 29 Apr 2018 23:04:21 +0200 Subject: [PATCH 212/247] add test alxinho1.bas This test should have been included in the last commit. --- tests/functional/alxinho1.bas | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 tests/functional/alxinho1.bas diff --git a/tests/functional/alxinho1.bas b/tests/functional/alxinho1.bas new file mode 100644 index 000000000..675a5b539 --- /dev/null +++ b/tests/functional/alxinho1.bas @@ -0,0 +1,4 @@ + + +DIM b = @a(0) + From 84fc13448211850033b04f15f6d3df4eb922647c Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 29 Apr 2018 23:08:13 +0200 Subject: [PATCH 213/247] bugfix: crash on constant dim elements Was crashing on correct programs like: CONST xx as UByte = 7 DIM c(1) as Ubyte = {xx, xx} Fixed. --- api/check.py | 4 ++-- arch/zx48k/translator.py | 4 ++-- tests/functional/dim_const0.asm | 40 +++++++++++++++++++++++++++++++++ tests/functional/dim_const0.bas | 3 +++ 4 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 tests/functional/dim_const0.asm create mode 100644 tests/functional/dim_const0.bas diff --git a/api/check.py b/api/check.py index 79da537b5..1a9f243e9 100644 --- a/api/check.py +++ b/api/check.py @@ -259,9 +259,9 @@ def is_CONST(*p): def is_static(*p): """ A static value (does not change at runtime) - which is known at compile time + which is known at compile time """ - return all(is_SYMBOL('CONST', x) or + return all(is_CONST(x) or is_number(x) or is_const(x) for x in p) diff --git a/arch/zx48k/translator.py b/arch/zx48k/translator.py index 48cccfaa6..9e5a81ccc 100644 --- a/arch/zx48k/translator.py +++ b/arch/zx48k/translator.py @@ -1215,9 +1215,9 @@ def default_value(cls, type_, expr): # TODO: This function must be moved to api """ assert isinstance(type_, symbols.TYPE) assert type_.is_basic - assert isinstance(expr, symbols.NUMBER) or isinstance(expr, symbols.CONST) + assert check.is_static(expr) - if isinstance(expr, symbols.CONST): # a constant expression like @label + 1 + if isinstance(expr, (symbols.CONST, symbols.VAR)): # a constant expression like @label + 1 if type_ in (cls.TYPE(TYPE.float_), cls.TYPE(TYPE.string)): syntax_error(expr.lineno, "Can't convert non-numeric value to {0} at compile time".format(type_.name)) return [''] diff --git a/tests/functional/dim_const0.asm b/tests/functional/dim_const0.asm new file mode 100644 index 000000000..7277713b2 --- /dev/null +++ b/tests/functional/dim_const0.asm @@ -0,0 +1,40 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_c: + DEFW 0000h + DEFB 01h + DEFB 7 + DEFB 7 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/dim_const0.bas b/tests/functional/dim_const0.bas new file mode 100644 index 000000000..56a40d49d --- /dev/null +++ b/tests/functional/dim_const0.bas @@ -0,0 +1,3 @@ +CONST xx as UByte = 7 +DIM c(1) as Ubyte = {xx, xx} + From 4a3577dfa3cc857b924796bf0b9346a312618016 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 1 May 2018 21:20:00 +0200 Subject: [PATCH 214/247] comment typos cleanup --- api/global_.py | 2 +- zxbparser.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/global_.py b/api/global_.py index 834977af3..422d6c7ed 100644 --- a/api/global_.py +++ b/api/global_.py @@ -144,4 +144,4 @@ DATA_LABELS = {} # Maps declared labels to current data ptr DATA_PTR_CURRENT = None DATA_IS_USED = False -DATA_FUNCTIONS = [] # Counts the number of funcptr emmited +DATA_FUNCTIONS = [] # Counts the number of funcptrs emitted diff --git a/zxbparser.py b/zxbparser.py index c2e2a6973..4f3642789 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -688,7 +688,7 @@ def p_var_decl_ini(p): SYMBOL_TABLE.declare_const(p[2][0][0], p[2][0][1], p[3], default_value=defval) - if defval is None: # Okay do a delayed initalization + if defval is None: # Okay do a delayed initialization p[0] = make_sentence('LET', SYMBOL_TABLE.access_var(p[2][0][0], p.lineno(1)), value) From 39ae35422d52eade2bd2571bea4b0a294cc8b3d0 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 1 May 2018 21:21:53 +0200 Subject: [PATCH 215/247] improvement: funcdecls now have their own lineno A function declaration can start at a given line and the function id being (mis)used previously or declared in the next (continued _) line. --- symbols/funcdecl.py | 5 +++-- tests/symbols/test_symbolFUNCDECL.py | 4 ++-- zxbparser.py | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/symbols/funcdecl.py b/symbols/funcdecl.py index 68c5d185a..07e04a792 100644 --- a/symbols/funcdecl.py +++ b/symbols/funcdecl.py @@ -18,9 +18,10 @@ class SymbolFUNCDECL(Symbol): """ Defines a Function declaration """ - def __init__(self, entry): + def __init__(self, entry, lineno): super(SymbolFUNCDECL, self).__init__() self.entry = entry # Symbol table entry + self.lineno = lineno # Line of this function declaration @property def entry(self): @@ -77,4 +78,4 @@ def make_node(cls, func_name, lineno, type_=None): return None entry.declared = True - return cls(entry) + return cls(entry, lineno) diff --git a/tests/symbols/test_symbolFUNCDECL.py b/tests/symbols/test_symbolFUNCDECL.py index 162850ac6..181b499aa 100644 --- a/tests/symbols/test_symbolFUNCDECL.py +++ b/tests/symbols/test_symbolFUNCDECL.py @@ -14,10 +14,10 @@ class TestSymbolFUNCDECL(TestCase): def setUp(self): api.global_.SYMBOL_TABLE = api.symboltable.SymbolTable() self.f = gl.SYMBOL_TABLE.declare_func('f', 1, type_=Type.ubyte) - self.s = FUNCDECL(self.f) + self.s = FUNCDECL(self.f, 1) def test__init__fail(self): - self.assertRaises(AssertionError, FUNCDECL, 'bla') + self.assertRaises(AssertionError, FUNCDECL, 'bla', 1) def test_entry__getter(self): self.assertEqual(self.s.entry, self.f) diff --git a/zxbparser.py b/zxbparser.py index 4f3642789..c1b942e52 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -2825,7 +2825,7 @@ def p_function_header_pre(p): return if FUNCTION_LEVEL[-1].kind == KIND.function: - api.check.check_type_is_explicit(p[0].entry.lineno, p[0].entry.name, p[3]) + api.check.check_type_is_explicit(p[0].lineno, p[0].entry.name, p[3]) if p[0].entry.convention == CONVENTION.fastcall and len(p[2]) > 1: kind = 'SUB' if FUNCTION_LEVEL[-1].kind == KIND.sub else 'FUNCTION' From c7fead6e336419507045d03331befa0468911784 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 1 May 2018 21:50:38 +0200 Subject: [PATCH 216/247] issue warning on undeclared function type --- api/check.py | 6 ++--- tests/functional/dup_func_decl.bas | 2 +- tests/functional/func0.asm | 43 ++++++++++++++++++++++++++++++ tests/functional/func0.bas | 6 +++++ tests/functional/param3.bas | 2 +- tests/functional/test_errmsg.txt | 2 ++ zxbparser.py | 2 ++ 7 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 tests/functional/func0.asm create mode 100644 tests/functional/func0.bas diff --git a/api/check.py b/api/check.py index 1a9f243e9..6817bb29b 100644 --- a/api/check.py +++ b/api/check.py @@ -77,13 +77,11 @@ def check_is_declared_explicit(lineno, id_, classname='variable'): def check_type_is_explicit(lineno, id_, type_): - if not config.OPTIONS.strict.value: - return # not in strict mode. Nothing to do - from symbols.type_ import SymbolTYPE assert isinstance(type_, SymbolTYPE) if type_.implicit: - api.errmsg.syntax_error_undeclared_type(lineno, id_) + if config.OPTIONS.strict.value: + api.errmsg.syntax_error_undeclared_type(lineno, id_) def check_call_arguments(lineno, id_, args): diff --git a/tests/functional/dup_func_decl.bas b/tests/functional/dup_func_decl.bas index ead72b4f0..175cd8ddd 100644 --- a/tests/functional/dup_func_decl.bas +++ b/tests/functional/dup_func_decl.bas @@ -1,6 +1,6 @@ -declare function f() +declare function f() as float declare function f() diff --git a/tests/functional/func0.asm b/tests/functional/func0.asm new file mode 100644 index 000000000..c6df31a38 --- /dev/null +++ b/tests/functional/func0.asm @@ -0,0 +1,43 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +_f: + push ix + ld ix, 0 + add ix, sp +_f__leave: + ld sp, ix + pop ix + ret + +ZXBASIC_USER_DATA: + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/func0.bas b/tests/functional/func0.bas new file mode 100644 index 000000000..662b647d9 --- /dev/null +++ b/tests/functional/func0.bas @@ -0,0 +1,6 @@ +' simple func declaration with default float type +' should issue a warning + +function f() +end function + diff --git a/tests/functional/param3.bas b/tests/functional/param3.bas index 3ff66b4c3..598a80512 100644 --- a/tests/functional/param3.bas +++ b/tests/functional/param3.bas @@ -1,6 +1,6 @@ ' Declare a parameter of type string using $ sigil suffix -declare function test(s$) +declare function test(s$) as float function test$(s$) return s$ + "A" diff --git a/tests/functional/test_errmsg.txt b/tests/functional/test_errmsg.txt index 32ca5daf9..37357edef 100644 --- a/tests/functional/test_errmsg.txt +++ b/tests/functional/test_errmsg.txt @@ -131,4 +131,6 @@ let_array_substr8.bas:3: Array 'a' has 1 dimensions, not 2 let_array_wrong_dims.bas:2: Array 'a' has 1 dimensions, not 2 >>> process_file('alxinho1.bas') alxinho1.bas:3: Undeclared array "a" +>>> process_file('func0.bas') +func0.bas:5: warning: Using default implicit type 'float' for 'f' diff --git a/zxbparser.py b/zxbparser.py index c1b942e52..65fa18e7e 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -2792,6 +2792,8 @@ def p_function_header_pre(p): previoustype_ = p[0].type_ if not p[3].implicit or p[0].entry.type_ is None or p[0].entry.type_ == TYPE.unknown: p[0].type_ = p[3] + if p[3].implicit and p[0].entry.kind == KIND.function: + api.errmsg.warning_implicit_type(p[3].lineno, p[0].entry.name, p[0].type_) if forwarded and previoustype_ != p[0].type_: api.errmsg.syntax_error_func_type_mismatch(lineno, p[0].entry) From b9904c832c62a1aaeb3898489f3eddecd02a0560 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 1 May 2018 22:16:07 +0200 Subject: [PATCH 217/247] bugfix: bad sigil being accepted DIM a$ as Float was being accepted (wrong declaration). Fixed. --- api/symboltable.py | 7 +++++-- tests/functional/bad_sigil.bas | 5 +++++ tests/functional/test_errmsg.txt | 3 +++ 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 tests/functional/bad_sigil.bas diff --git a/api/symboltable.py b/api/symboltable.py index e3af34316..2e65d40e7 100644 --- a/api/symboltable.py +++ b/api/symboltable.py @@ -176,6 +176,8 @@ def declare(self, id_, lineno, entry): if id2[-1] in DEPRECATED_SUFFIXES: id2 = id2[:-1] # Remove it type_ = symbols.TYPEREF(self.basic_types[SUFFIX_TYPE[id_[-1]]], lineno) # Overrides type_ + if entry.type_ is not None and not entry.type_.implicit and type_ != entry.type_: + syntax_error(lineno, "expected type {2} for '{0}', got {1}".format(id_, entry.type_.name, type_.name)) # Checks if already declared if self[self.current_scope][id2] is not None: @@ -190,10 +192,11 @@ def declare(self, id_, lineno, entry): # HINT: The following should be done by the respective callers! # entry.callable = None # True if function, strings or arrays + # entry.class_ = None # TODO: important + entry.forwarded = False # True for a function header entry.mangled = '%s%s%s' % (self.mangle, global_.MANGLE_CHR, entry.name) # Mangled name - # entry.class_ = None # TODO: important - entry.type_ = type_ # HINT: Nonsense. Must be set at declaration or later + entry.type_ = type_ # type_ now reflects entry sigil (i.e. a$ => 'string' type) if any entry.scopeRef = self[self.current_scope] return entry diff --git a/tests/functional/bad_sigil.bas b/tests/functional/bad_sigil.bas new file mode 100644 index 000000000..1fceb3a99 --- /dev/null +++ b/tests/functional/bad_sigil.bas @@ -0,0 +1,5 @@ + +sub x(y$ as Float) + y = "5" +end sub + diff --git a/tests/functional/test_errmsg.txt b/tests/functional/test_errmsg.txt index 37357edef..696df47ed 100644 --- a/tests/functional/test_errmsg.txt +++ b/tests/functional/test_errmsg.txt @@ -133,4 +133,7 @@ let_array_wrong_dims.bas:2: Array 'a' has 1 dimensions, not 2 alxinho1.bas:3: Undeclared array "a" >>> process_file('func0.bas') func0.bas:5: warning: Using default implicit type 'float' for 'f' +>>> process_file('bad_sigil.bas') +bad_sigil.bas:2: expected type string for 'y$', got float +bad_sigil.bas:2: warning: Parameter 'y' is never used From fc8c4903aa9504f535c8c0d6c14d5f49fba031b6 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 1 May 2018 22:32:22 +0200 Subject: [PATCH 218/247] bugfix: prevent duplicated error / warning lines a = 4 a = 5 (for example), produced duplicated error msgs. Fixed using a cache. --- api/errmsg.py | 14 ++++++++++---- api/global_.py | 5 +++++ asmparse.py | 1 + tests/functional/test_errmsg.txt | 3 --- zxbparser.py | 1 + zxbpp.py | 1 + 6 files changed, 18 insertions(+), 7 deletions(-) diff --git a/api/errmsg.py b/api/errmsg.py index ac58ae279..0562a343d 100644 --- a/api/errmsg.py +++ b/api/errmsg.py @@ -17,6 +17,14 @@ __all__ = ['syntax_error', 'warning'] +def msg_output(msg): + if msg in global_.error_msg_cache: + return + + OPTIONS.stderr.value.write("%s\n" % msg) + global_.error_msg_cache.add(msg) + + def syntax_error(lineno, msg): """ Generic syntax error routine """ @@ -24,8 +32,7 @@ def syntax_error(lineno, msg): msg = 'Too many errors. Giving up!' msg = "%s:%i: %s" % (global_.FILENAME, lineno, msg) - - OPTIONS.stderr.value.write("%s\n" % msg) + msg_output(msg) if global_.has_errors > OPTIONS.max_syntax_errors.value: sys.exit(1) @@ -37,8 +44,7 @@ def warning(lineno, msg): """ Generic warning error routine """ msg = "%s:%i: warning: %s" % (global_.FILENAME, lineno, msg) - OPTIONS.stderr.value.write("%s\n" % msg) - + msg_output(msg) global_.has_warnings += 1 diff --git a/api/global_.py b/api/global_.py index 422d6c7ed..488dee901 100644 --- a/api/global_.py +++ b/api/global_.py @@ -145,3 +145,8 @@ DATA_PTR_CURRENT = None DATA_IS_USED = False DATA_FUNCTIONS = [] # Counts the number of funcptrs emitted + +# ---------------------------------------------------------------------- +# Cache of Message errors to avoid repetition +# ---------------------------------------------------------------------- +error_msg_cache = set() diff --git a/asmparse.py b/asmparse.py index 21f538a0d..934422842 100755 --- a/asmparse.py +++ b/asmparse.py @@ -79,6 +79,7 @@ def init(): AUTORUN_ADDR = None # Where to start the execution automatically NAMESPACE = GLOBAL_NAMESPACE # Current namespace (defaults to ''). It's a prefix added to each global label gl.has_errors = 0 + gl.error_msg_cache.clear() class Asm(AsmInstruction): diff --git a/tests/functional/test_errmsg.txt b/tests/functional/test_errmsg.txt index 696df47ed..c2080069f 100644 --- a/tests/functional/test_errmsg.txt +++ b/tests/functional/test_errmsg.txt @@ -47,10 +47,8 @@ poke5.bas:4: Variable 'a' is an array and cannot be used in this context >>> process_file('arrlabels10.bas') arrlabels10.bas:3: warning: Using default implicit type 'float' for 'a' arrlabels10.bas:3: Can't convert non-numeric value to float at compile time -arrlabels10.bas:3: Can't convert non-numeric value to float at compile time >>> process_file('arrlabels10c.bas') arrlabels10c.bas:3: Can't convert non-numeric value to string at compile time -arrlabels10c.bas:3: Can't convert non-numeric value to string at compile time >>> process_file('arrlabels10d.bas') arrlabels10d.bas:3: Undeclared array "a" >>> process_file('arrlabels11.bas') @@ -78,7 +76,6 @@ defsbad.asm:2: too many arguments for DEFS >>> process_file('asmprepro.asm') asmprepro.asm:8: warning: Recursive inclusion asmprepro.asm:12: warning: Recursive inclusion -asmprepro.asm:12: warning: Recursive inclusion >>> process_file('strict.bas') strict.bas:2: warning: Using default implicit type 'float' for 'b' strict.bas:4: strict mode: missing type declaration for 'a' diff --git a/zxbparser.py b/zxbparser.py index 65fa18e7e..bc2b3cc14 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -146,6 +146,7 @@ def init(): del gl.DATAS[:] gl.DATA_PTR_CURRENT = api.utils.current_data_label() gl.DATA_FUNCTIONS = [] + gl.error_msg_cache.clear() # ---------------------------------------------------------------------- diff --git a/zxbpp.py b/zxbpp.py index beff3efab..5aaf9819c 100755 --- a/zxbpp.py +++ b/zxbpp.py @@ -80,6 +80,7 @@ def init(): ENABLED = True IFDEFS = [] global_.has_errors = 0 + global_.error_msg_cache.clear() parser.defaulted_states = {} ID_TABLE = DefinesTable() del CURRENT_FILE[:] From 27a00799b2b35ebd09f082e4d04a5b23f693d22d Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 1 May 2018 23:13:24 +0200 Subject: [PATCH 219/247] feature: warn about implicit type in parameters --- api/symboltable.py | 2 + tests/functional/params_implicit.asm | 104 +++++++++++++++++++++++++++ tests/functional/params_implicit.bas | 5 ++ tests/functional/test_errmsg.txt | 3 + 4 files changed, 114 insertions(+) create mode 100644 tests/functional/params_implicit.asm create mode 100644 tests/functional/params_implicit.bas diff --git a/api/symboltable.py b/api/symboltable.py index 2e65d40e7..cfbf78077 100644 --- a/api/symboltable.py +++ b/api/symboltable.py @@ -697,6 +697,8 @@ def declare_param(self, id_, lineno, type_=None): if entry is None: return entry.declared = True + if entry.type_.implicit: + warning_implicit_type(lineno, id_, type_) return entry def declare_array(self, id_, lineno, type_, bounds, default_value=None): diff --git a/tests/functional/params_implicit.asm b/tests/functional/params_implicit.asm new file mode 100644 index 000000000..f5e017a9b --- /dev/null +++ b/tests/functional/params_implicit.asm @@ -0,0 +1,104 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +_x: + push ix + ld ix, 0 + add ix, sp + ld a, 083h + ld de, 00020h + ld bc, 00000h + ld hl, 4 + call __PSTOREF +_x__leave: + ld sp, ix + pop ix + exx + pop hl + pop bc + pop bc + ex (sp), hl + exx + ret +#line 1 "pstoref.asm" + + ; Stores FP number in A ED CB at location HL+IX + ; HL = Offset + ; IX = Stack Frame + ; A ED CB = FP Number + +#line 1 "storef.asm" + +__PISTOREF: ; Indect Stores a float (A, E, D, C, B) at location stored in memory, pointed by (IX + HL) + push de + ex de, hl ; DE <- HL + push ix + pop hl ; HL <- IX + add hl, de ; HL <- IX + HL + pop de + +__ISTOREF: ; Load address at hl, and stores A,E,D,C,B registers at that address. Modifies A' register + ex af, af' + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex af, af' + +__STOREF: ; Stores the given FP number in A EDCB at address HL + ld (hl), a + inc hl + ld (hl), e + inc hl + ld (hl), d + inc hl + ld (hl), c + inc hl + ld (hl), b + ret + +#line 7 "pstoref.asm" + + ; Stored a float number in A ED CB into the address pointed by IX + HL +__PSTOREF: + push de + ex de, hl ; DE <- HL + push ix + pop hl ; HL <- IX + add hl, de ; HL <- IX + DE + pop de + jp __STOREF + +#line 37 "params_implicit.bas" + +ZXBASIC_USER_DATA: + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/params_implicit.bas b/tests/functional/params_implicit.bas new file mode 100644 index 000000000..e74f44c8c --- /dev/null +++ b/tests/functional/params_implicit.bas @@ -0,0 +1,5 @@ +REM issues a warning on y type not being explicit +SUB x(y) + y = 5 +END SUB + diff --git a/tests/functional/test_errmsg.txt b/tests/functional/test_errmsg.txt index c2080069f..63cc48e00 100644 --- a/tests/functional/test_errmsg.txt +++ b/tests/functional/test_errmsg.txt @@ -133,4 +133,7 @@ func0.bas:5: warning: Using default implicit type 'float' for 'f' >>> process_file('bad_sigil.bas') bad_sigil.bas:2: expected type string for 'y$', got float bad_sigil.bas:2: warning: Parameter 'y' is never used +>>> process_file('params_implicit.bas') +params_implicit.bas:2: warning: Using default implicit type 'float' for 'y' +params_implicit.bas:2: warning: Parameter 'y' is never used From aa73469bcf9edc32b41d24a915d3748b497ec30f Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 17 Jun 2018 20:37:22 +0200 Subject: [PATCH 220/247] bugfix: crash on constant usage This fixes several bugs related to constant folding and inline usage. For example: CONST g as UInteger = 1 DIM f as UInteger LET f = 5 * g Reported by Haplo --- symbols/number.py | 88 +++++++++++------ tests/functional/const_expr.asm | 133 +++++++++++++++++++++++++ tests/functional/const_expr.bas | 63 ++++++++++++ tests/symbols/test_symbolNUMBER.py | 153 +++++++++++++++++++++++++++++ 4 files changed, 405 insertions(+), 32 deletions(-) create mode 100644 tests/functional/const_expr.asm create mode 100644 tests/functional/const_expr.bas diff --git a/symbols/number.py b/symbols/number.py index fbfd7a9f4..60b825740 100644 --- a/symbols/number.py +++ b/symbols/number.py @@ -15,6 +15,20 @@ from .symbol_ import Symbol from .type_ import SymbolTYPE from .type_ import Type as TYPE +from .const import SymbolCONST + + +def _get_val(other): + """ Given a Number, a Numeric Constant or a python number return its value + """ + assert isinstance(other, (numbers.Number, SymbolNUMBER, SymbolCONST)) + if isinstance(other, SymbolNUMBER): + return other.value + + if isinstance(other, SymbolCONST): + return other.expr.value + + return other class SymbolNUMBER(Symbol): @@ -79,57 +93,67 @@ def t(self): return str(self) def __eq__(self, other): - if not isinstance(other, (numbers.Number, SymbolNUMBER)): + if not isinstance(other, (numbers.Number, SymbolNUMBER, SymbolCONST)): return False - if isinstance(other, numbers.Number): - return self.value == other - - return self.value == other.value + return self.value == _get_val(other) def __lt__(self, other): - assert isinstance(other, (numbers.Number, SymbolNUMBER)) - - if isinstance(other, numbers.Number): - return self.value < other + return self.value < _get_val(other) - return self.value < other.value + def __le__(self, other): + return self.value <= _get_val(other) def __gt__(self, other): - assert isinstance(other, (numbers.Number, SymbolNUMBER)) + return self.value > _get_val(other) - if isinstance(other, numbers.Number): - return self.value > other - - return self.value > other.value + def __ge__(self, other): + return self.value >= _get_val(other) def __add__(self, other): - assert isinstance(other, (numbers.Number, SymbolNUMBER)) - if isinstance(other, SymbolNUMBER): - return SymbolNUMBER(self.value + other.value, self.lineno) + return SymbolNUMBER(self.value + _get_val(other), self.lineno) - return SymbolNUMBER(self.value + other, self.lineno) + def __radd__(self, other): + return SymbolNUMBER(_get_val(other) + self.value, self.lineno) def __sub__(self, other): - assert isinstance(other, (numbers.Number, SymbolNUMBER)) - if isinstance(other, SymbolNUMBER): - return SymbolNUMBER(self.value - other.value, self.lineno) + return SymbolNUMBER(self.value - _get_val(other), self.lineno) - return SymbolNUMBER(self.value - other, self.lineno) + def __rsub__(self, other): + return SymbolNUMBER(_get_val(other) - self.value, self.lineno) def __mul__(self, other): - assert isinstance(other, (numbers.Number, SymbolNUMBER)) - if isinstance(other, SymbolNUMBER): - return SymbolNUMBER(self.value * other.value, self.lineno) + return SymbolNUMBER(self.value * _get_val(other), self.lineno) - return SymbolNUMBER(self.value * other, self.lineno) + def __rmul__(self, other): + return SymbolNUMBER(_get_val(other) * self.value, self.lineno) def __truediv__(self, other): - assert isinstance(other, (numbers.Number, SymbolNUMBER)) - if isinstance(other, SymbolNUMBER): - return SymbolNUMBER(self.value / other.value, self.lineno) - - return SymbolNUMBER(self.value / other, self.lineno) + return SymbolNUMBER(self.value / _get_val(other), self.lineno) def __div__(self, other): return self.__truediv__(other) + + def __rtruediv__(self, other): + return SymbolNUMBER(_get_val(other) / self.value, self.lineno) + + def __rdiv__(self, other): + return self.__rtruediv__(other) + + def __or__(self, other): + return SymbolNUMBER(self.value | _get_val(other), self.lineno) + + def __ror__(self, other): + return SymbolNUMBER(_get_val(other | self.value), self.lineno) + + def __and__(self, other): + return SymbolNUMBER(self.value & _get_val(other), self.lineno) + + def __rand__(self, other): + return SymbolNUMBER(_get_val(other) & self.value, self.lineno) + + def __mod__(self, other): + return SymbolNUMBER(self.value % _get_val(other), self.lineno) + + def __rmod__(self, other): + return SymbolNUMBER(_get_val(other) % self.value, self.lineno) diff --git a/tests/functional/const_expr.asm b/tests/functional/const_expr.asm new file mode 100644 index 000000000..2668c3daa --- /dev/null +++ b/tests/functional/const_expr.asm @@ -0,0 +1,133 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld a, 6 + ld (_f), a + ld a, 4 + ld (_f), a + ld a, 5 + ld (_f), a + ld a, 5 + ld (_f), a + ld a, 6 + ld (_f), a + ld a, 252 + ld (_f), a + ld a, 5 + ld (_f), a + xor a + ld (_f), a + ld a, 2 + ld (_f), a + xor a + ld (_f), a + ld a, 1 + ld (_f), a + ld a, 1 + ld (_f), a + ld a, 1 + ld (_f), a + ld a, 5 + ld (_f), a + ld a, 53 + ld (_f), a + ld a, 1 + ld (_f), a + ld a, 5 + ld (_f), a + ld a, 5 + ld (_f), a + ld a, 5 + ld (_f), a + ld a, 1 + ld (_f), a + ld a, 5 + ld (_f), a + ld a, 1 + ld (_f), a + ld a, 1 + ld (_f), a + ld a, 1 + ld (_f), a + ld a, 1 + ld (_f), a + ld a, 1 + ld (_f), a + xor a + ld (_f), a + xor a + ld (_f), a + ld a, 1 + ld (_f), a + xor a + ld (_f), a + xor a + ld (_f), a + ld a, 1 + ld (_f), a + xor a + ld (_f), a + xor a + ld (_f), a + ld a, 1 + ld (_f), a + xor a + ld (_f), a + xor a + ld (_f), a + ld a, 1 + ld (_f), a + xor a + ld (_f), a + xor a + ld (_f), a + ld a, 1 + ld (_f), a + xor a + ld (_f), a + ld a, 1 + ld (_f), a + ld a, 1 + ld (_f), a + ld a, 1 + ld (_f), a + ld a, 1 + ld (_f), a + xor a + ld (_f), a + ld a, 1 + ld (_f), a + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_f: + DEFB 00 + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/const_expr.bas b/tests/functional/const_expr.bas new file mode 100644 index 000000000..6c4dccbac --- /dev/null +++ b/tests/functional/const_expr.bas @@ -0,0 +1,63 @@ + +const g as Uinteger = 1 + +f = 5 + g +f = 5 - g +f = 5 * g +f = 5 / g + +f = g + 5 +f = g - 5 +f = g * 5 +f = g / 5 + +f = g + g +f = g - g +f = g * g +f = g / g + +f = g ^ 5 +f = 5 ^ g +f = 5 ^ 5 +f = g ^ g + +f = 5 | 5 +f = 5 | g +f = g | 5 +f = g | g + +f = 5 & 5 +f = g & 5 +f = 5 & g +f = g & g + +f = 5 mod 2 +f = g mod 5 +f = 5 mod g +f = g mod g + +f = (5 = 5) +f = (5 = g) +f = (g = 5) +f = (g = g) + +f = (5 < 5) +f = (5 < g) +f = (g < 5) +f = (g < g) + +f = (5 > 5) +f = (5 > g) +f = (g > 5) +f = (g > g) + +f = (5 <= 5) +f = (5 <= g) +f = (g <= 5) +f = (g <= g) + +f = (5 >= 5) +f = (5 >= g) +f = (g >= 5) +f = (g >= g) + diff --git a/tests/symbols/test_symbolNUMBER.py b/tests/symbols/test_symbolNUMBER.py index 2cf67097c..c0f228d01 100644 --- a/tests/symbols/test_symbolNUMBER.py +++ b/tests/symbols/test_symbolNUMBER.py @@ -7,6 +7,7 @@ from api.constants import TYPE from symbols import NUMBER from symbols import BASICTYPE +from symbols import CONST class TestSymbolNUMBER(TestCase): @@ -41,10 +42,162 @@ def test__cmp__(self): self.assertGreater(m, n) self.assertLess(n, m) + def test__cmp__const(self): + n = NUMBER(0, lineno=1) + m = CONST(NUMBER(1, lineno=2), lineno=2) + m2 = CONST(NUMBER(0, lineno=3), lineno=3) + + self.assertNotEqual(n, m) + self.assertEqual(n, n) + + self.assertNotEqual(n, 2) + self.assertEqual(n, 0) + self.assertGreater(n, -1) + self.assertLess(n, 1) + + self.assertGreater(m, n) + self.assertLess(n, m) + self.assertEqual(n, m2) + self.assertEqual(m2, n) + def test__t(self): n = NUMBER(3.14, 1) self.assertEqual(n.t, '3.14') + def test__add__num_num(self): + a = NUMBER(1, 0) + b = NUMBER(2, 0) + self.assertEqual((a + b).t, '3') + + def test__add__num_const(self): + a = NUMBER(1, 0) + b = CONST(NUMBER(2, 0), 0) + self.assertEqual((a + b).t, '3') + + def test__add__num_value(self): + a = NUMBER(1, 0) + self.assertEqual((a + 2).t, '3') + + def test__radd__num_const(self): + a = NUMBER(1, 0) + b = CONST(NUMBER(2, 0), 0) + self.assertEqual((b + a).t, '3') + + def test__radd__num_value(self): + a = NUMBER(1, 0) + self.assertEqual((2 + a).t, '3') + + def test__sub__num_num(self): + a = NUMBER(1, 0) + b = NUMBER(2, 0) + self.assertEqual((a - b).t, '-1') + + def test__sub__num_const(self): + a = NUMBER(1, 0) + b = CONST(NUMBER(2, 0), 0) + self.assertEqual((a - b).t, '-1') + + def test__sub__num_value(self): + a = NUMBER(1, 0) + self.assertEqual((a - 2).t, '-1') + + def test__rsub__num_const(self): + a = NUMBER(2, 0) + b = CONST(NUMBER(1, 0), 0) + self.assertEqual((b - a).t, '-1') + + def test__rsub__num_value(self): + a = NUMBER(2, 0) + self.assertEqual((1 - a).t, '-1') + + def test__mul__num_num(self): + a = NUMBER(3, 0) + b = NUMBER(2, 0) + self.assertEqual((a * b).t, '6') + + def test__mul__num_const(self): + a = NUMBER(3, 0) + b = CONST(NUMBER(2, 0), 0) + self.assertEqual((a * b).t, '6') + + def test__mul__num_value(self): + a = NUMBER(3, 0) + self.assertEqual((a * 2).t, '6') + + def test__rmul__num_const(self): + a = NUMBER(3, 0) + b = CONST(NUMBER(2, 0), 0) + self.assertEqual((b * a).t, '6') + + def test__rmul__num_value(self): + a = NUMBER(3, 0) + self.assertEqual((2 * a).t, '6') + + def test__div__num_num(self): + a = NUMBER(3, 0) + b = NUMBER(-2, 0) + self.assertEqual((a / b).t, str(a.value / b.value)) + + def test__div__num_const(self): + a = NUMBER(3, 0) + b = CONST(NUMBER(-2, 0), 0) + self.assertEqual((a / b).t, str(a.value / b.expr.value)) + + def test__div__num_value(self): + a = NUMBER(3, 0) + self.assertEqual((a / -2.0).t, '-1.5') + + def test__rdiv__num_const(self): + a = CONST(NUMBER(-3, 0), 0) + b = NUMBER(2, 0) + self.assertEqual((a / b).t, str(a.expr.value / b.value)) + + def test__rdiv__num_value(self): + a = NUMBER(-2, 0) + self.assertEqual((3.0 / a).t, '-1.5') + + def test__bor__val_num(self): + b = NUMBER(5, 0) + self.assertEqual((3 | b).t, '7') + + def test__bor__num_val(self): + b = NUMBER(5, 0) + self.assertEqual((b | 3).t, '7') + + def test__band__num_val(self): + b = NUMBER(5, 0) + self.assertEqual((b & 3).t, '1') + + def test__band__val_num(self): + b = NUMBER(5, 0) + self.assertEqual((3 & b).t, '1') + + def test__mod__num_val(self): + b = NUMBER(5, 0) + self.assertEqual((b % 3).t, '2') + + def test__mod__val_num(self): + b = NUMBER(3, 0) + self.assertEqual((5 % b).t, '2') + + def test__le__val_num(self): + b = NUMBER(3, 0) + self.assertLessEqual(2, b) + + def test__le__num_num(self): + a = NUMBER(2, 0) + b = NUMBER(3, 0) + self.assertLessEqual(a, b) + + def test__ge__val_num(self): + b = NUMBER(1, 0) + self.assertGreaterEqual(2, b) + + def test__ge__num_num(self): + a = NUMBER(4, 0) + b = NUMBER(3, 0) + self.assertGreaterEqual(a, b) + if __name__ == '__main__': unittest.main() From 3a0219a91c85c51ac8399104ef4697ee10fff0cd Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 30 Jul 2018 23:54:38 +0200 Subject: [PATCH 221/247] bugfix: allows UTF-8 BOM signature --- api/utils.py | 2 +- tests/functional/utf-8-bom-asm.asm | 4 ++++ tests/functional/utf-8-bom-asm.bin | Bin 0 -> 1 bytes tests/functional/utf-8-bom-bas.asm | 36 +++++++++++++++++++++++++++++ tests/functional/utf-8-bom-bas.bas | 3 +++ 5 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 tests/functional/utf-8-bom-asm.asm create mode 100644 tests/functional/utf-8-bom-asm.bin create mode 100644 tests/functional/utf-8-bom-bas.asm create mode 100644 tests/functional/utf-8-bom-bas.bas diff --git a/api/utils.py b/api/utils.py index 7ee07b784..b33cd04bb 100644 --- a/api/utils.py +++ b/api/utils.py @@ -15,7 +15,7 @@ def read_txt_file(fname): """Reads a txt file, regardless of its encoding """ - encodings = ['utf-8', 'cp1252'] + encodings = ['utf-8-sig', 'cp1252'] with open(fname, 'rb') as f: content = bytes(f.read()) diff --git a/tests/functional/utf-8-bom-asm.asm b/tests/functional/utf-8-bom-asm.asm new file mode 100644 index 000000000..a4c59fe8a --- /dev/null +++ b/tests/functional/utf-8-bom-asm.asm @@ -0,0 +1,4 @@ +datosniveles: +nop +; This file contains an UTF-8 BOM and must be correctly parsed + diff --git a/tests/functional/utf-8-bom-asm.bin b/tests/functional/utf-8-bom-asm.bin new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/tests/functional/utf-8-bom-bas.asm b/tests/functional/utf-8-bom-bas.asm new file mode 100644 index 000000000..9c82cd247 --- /dev/null +++ b/tests/functional/utf-8-bom-bas.asm @@ -0,0 +1,36 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei +__LABEL__datosniveles: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/utf-8-bom-bas.bas b/tests/functional/utf-8-bom-bas.bas new file mode 100644 index 000000000..b0913caad --- /dev/null +++ b/tests/functional/utf-8-bom-bas.bas @@ -0,0 +1,3 @@ +datosniveles: + +REM this file contains an UTF-8 BOM at the beginning From 3485b4f40ea94a12ff98852f19fb7323981e578e Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 31 Jul 2018 23:05:59 +0200 Subject: [PATCH 222/247] =?UTF-8?q?Bump=20version:=201.8.3=20=E2=86=92=201?= =?UTF-8?q?.8.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- ChangeLog | 10 ++++++++++ version.py | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 46d8a63ec..7cbc04d94 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,4 +1,4 @@ [bumpversion] -current_version = 1.8.3 +current_version = 1.8.4 files = version.py diff --git a/ChangeLog b/ChangeLog index c044b35b0..756dfcd5d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +================================================================ +Changes from Version 1.8.3 to 1.8.4 +! Several bugfixes with contants declaration ++ Suport for UTF-8 BOM files +! Bugfixes with -O3 crash +! Fixes crash with arrays +! Other bugfixes and better stability +* Better warning explanation under some circumstances + ================================================================ Changes from Version 1.8.2 to 1.8.3 ! Bugfix in the peephole optimizer (-O2) @@ -12,6 +21,7 @@ Changes from Version 1.8.1 to 1.8.2 + Shorter and faster generated code (deep optimizations) ! Bugfix in the PRINT42 routine that now supports newlines, etc + Implemented routine input42 (INPUT42.BAS) for PRINT42 mode + ================================================================ Changes from Version 1.8.0 to 1.8.1 ! Bugfixes in the peephole optimizer diff --git a/version.py b/version.py index 32e3f09b9..f830c1dcc 100755 --- a/version.py +++ b/version.py @@ -1 +1 @@ -VERSION = '1.8.3' +VERSION = '1.8.4' From 4ff613815f3a98f6ed4af35213a71d18e3faf723 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 17 Aug 2018 00:04:08 +0200 Subject: [PATCH 223/247] bugfix: fix crash on wrong array definition Fix a regression with wrong line number index. --- tests/functional/array_err.bas | 3 +++ tests/functional/test_errmsg.txt | 2 ++ zxbparser.py | 9 +++++---- 3 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 tests/functional/array_err.bas diff --git a/tests/functional/array_err.bas b/tests/functional/array_err.bas new file mode 100644 index 000000000..7dd8a6d94 --- /dev/null +++ b/tests/functional/array_err.bas @@ -0,0 +1,3 @@ + +dim test(10,1) as ubyte => {{0,0,0,0,0,0,0,0,0,0,0}} + diff --git a/tests/functional/test_errmsg.txt b/tests/functional/test_errmsg.txt index 63cc48e00..f643f8f78 100644 --- a/tests/functional/test_errmsg.txt +++ b/tests/functional/test_errmsg.txt @@ -136,4 +136,6 @@ bad_sigil.bas:2: warning: Parameter 'y' is never used >>> process_file('params_implicit.bas') params_implicit.bas:2: warning: Using default implicit type 'float' for 'y' params_implicit.bas:2: warning: Parameter 'y' is never used +>>> process_file('array_err.bas') +array_err.bas:2: Mismatched vector size. Expected 11 elements, got 1. diff --git a/zxbparser.py b/zxbparser.py index bc2b3cc14..81f7a0e87 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -732,19 +732,20 @@ def p_arr_decl_initialized(p): def check_bound(boundlist, remaining): """ Checks if constant vector bounds matches the array one """ + lineno = p.lineno(8) if not boundlist: # Returns on empty list if not isinstance(remaining, list): return True # It's OK :-) - syntax_error(p.lineno(9), 'Unexpected extra vector dimensions. It should be %i' % len(remaining)) + syntax_error(lineno, 'Unexpected extra vector dimensions. It should be %i' % len(remaining)) if not isinstance(remaining, list): - syntax_error(p.lineno(9), 'Mismatched vector size. Missing %i extra dimension(s)' % len(boundlist)) + syntax_error(lineno, 'Mismatched vector size. Missing %i extra dimension(s)' % len(boundlist)) return False if len(remaining) != boundlist[0].count: - syntax_error(p.lineno(9), 'Mismatched vector size. Expected %i elements, got %i.' % (boundlist[0].count, - len(remaining))) + syntax_error(lineno, 'Mismatched vector size. Expected %i elements, got %i.' % (boundlist[0].count, + len(remaining))) return False # It's wrong. :-( for row in remaining: From ed2b58c820a8e3538cf5a29d23be1a539c6ddaaf Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 17 Aug 2018 00:25:36 +0200 Subject: [PATCH 224/247] =?UTF-8?q?Bump=20version:=201.8.4=20=E2=86=92=201?= =?UTF-8?q?.8.5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- ChangeLog | 4 ++++ version.py | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 7cbc04d94..191838f0e 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,4 +1,4 @@ [bumpversion] -current_version = 1.8.4 +current_version = 1.8.5 files = version.py diff --git a/ChangeLog b/ChangeLog index 756dfcd5d..230967669 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +================================================================ +Changes from Version 1.8.4 to 1.8.5 +! Bugfix: crash on bad array declaration + ================================================================ Changes from Version 1.8.3 to 1.8.4 ! Several bugfixes with contants declaration diff --git a/version.py b/version.py index f830c1dcc..181785c23 100755 --- a/version.py +++ b/version.py @@ -1 +1 @@ -VERSION = '1.8.4' +VERSION = '1.8.5' From f9c8cb75106d8db632a9bd0c697d5117ce8b4596 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Thu, 20 Sep 2018 23:38:52 +0200 Subject: [PATCH 225/247] bugfix: END sentence End sentence was not being emitted correctly. Fixed. --- arch/zx48k/translator.py | 4 +-- tests/functional/opt1_endtest.asm | 42 +++++++++++++++++++++++++++++++ tests/functional/opt1_endtest.bas | 4 +++ tests/functional/opt3_endtest.asm | 38 ++++++++++++++++++++++++++++ tests/functional/opt3_endtest.bas | 4 +++ 5 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 tests/functional/opt1_endtest.asm create mode 100644 tests/functional/opt1_endtest.bas create mode 100644 tests/functional/opt3_endtest.asm create mode 100644 tests/functional/opt3_endtest.bas diff --git a/arch/zx48k/translator.py b/arch/zx48k/translator.py index 9e5a81ccc..be043866a 100644 --- a/arch/zx48k/translator.py +++ b/arch/zx48k/translator.py @@ -318,9 +318,9 @@ def visit_STRING(self, node): yield node.t def visit_END(self, node): - arg = (yield node.children[0]) + yield node.children[0] __DEBUG__('END') - self.emit('end', arg) + self.emit('end', node.children[0].t) def visit_ERROR(self, node): # Raises an error diff --git a/tests/functional/opt1_endtest.asm b/tests/functional/opt1_endtest.asm new file mode 100644 index 000000000..c0bafc840 --- /dev/null +++ b/tests/functional/opt1_endtest.asm @@ -0,0 +1,42 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, (_N) + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + ld hl, 0 + ld b, h + ld c, l + jp __END_PROGRAM + +ZXBASIC_USER_DATA: +_N: + DEFB 39h + DEFB 30h + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/opt1_endtest.bas b/tests/functional/opt1_endtest.bas new file mode 100644 index 000000000..21529525a --- /dev/null +++ b/tests/functional/opt1_endtest.bas @@ -0,0 +1,4 @@ + +DIM N as uinteger = 12345 +end N + diff --git a/tests/functional/opt3_endtest.asm b/tests/functional/opt3_endtest.asm new file mode 100644 index 000000000..5f8ee7ece --- /dev/null +++ b/tests/functional/opt3_endtest.asm @@ -0,0 +1,38 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld bc, (_N) +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + pop iy + pop ix + exx + ei + ret +__CALL_BACK__: + DEFW 0 + ld bc, 0 + jp __END_PROGRAM + +ZXBASIC_USER_DATA: +_N: + DEFB 39h + DEFB 30h + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/opt3_endtest.bas b/tests/functional/opt3_endtest.bas new file mode 100644 index 000000000..21529525a --- /dev/null +++ b/tests/functional/opt3_endtest.bas @@ -0,0 +1,4 @@ + +DIM N as uinteger = 12345 +end N + From f034ee439a81999707664f00d3201e43801e7dd7 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Thu, 20 Sep 2018 23:40:25 +0200 Subject: [PATCH 226/247] =?UTF-8?q?Bump=20version:=201.8.5=20=E2=86=92=201?= =?UTF-8?q?.8.6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 191838f0e..539791f66 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,4 +1,4 @@ [bumpversion] -current_version = 1.8.5 +current_version = 1.8.6 files = version.py diff --git a/version.py b/version.py index 181785c23..40c5bab5f 100755 --- a/version.py +++ b/version.py @@ -1 +1 @@ -VERSION = '1.8.5' +VERSION = '1.8.6' From 2ce9f46acc43cf1ef327f412849fbdf9845eea53 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 24 Sep 2018 00:32:05 +0200 Subject: [PATCH 227/247] bugfix: do not remove asm block upon jump ASM blocks are NEVER optimized --- arch/zx48k/backend/__init__.py | 3 ++- tests/functional/opt1_nolabel.asm | 43 +++++++++++++++++++++++++++++++ tests/functional/opt1_nolabel.bas | 14 ++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 tests/functional/opt1_nolabel.asm create mode 100644 tests/functional/opt1_nolabel.bas diff --git a/arch/zx48k/backend/__init__.py b/arch/zx48k/backend/__init__.py index cbf1fb983..0ed3d67e1 100644 --- a/arch/zx48k/backend/__init__.py +++ b/arch/zx48k/backend/__init__.py @@ -2716,7 +2716,8 @@ def output_join(output, new_chunk): # # Into: # jp XXX - if OPT31 and i1 == 'jp' and not condition(output[-1]) and i2 is not None and i2[-1] != ':': + if OPT31 and i1 == 'jp' and not condition(output[-1]) and i2 is not None and \ + i2[-1] != ':' and new_chunk[0] not in ASMS: new_chunk.pop(0) changed = True continue diff --git a/tests/functional/opt1_nolabel.asm b/tests/functional/opt1_nolabel.asm new file mode 100644 index 000000000..f378d0b7f --- /dev/null +++ b/tests/functional/opt1_nolabel.asm @@ -0,0 +1,43 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei +#line 1 + ld hl, mygod +#line 2 + jp __LABEL__finish +mygod: + nop +#line 9 +__LABEL__finish: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/opt1_nolabel.bas b/tests/functional/opt1_nolabel.bas new file mode 100644 index 000000000..34153eb12 --- /dev/null +++ b/tests/functional/opt1_nolabel.bas @@ -0,0 +1,14 @@ + +ASM +ld hl, mygod +END ASM + +GOTO finish + +ASM +mygod: +nop +END ASM + +finish: + From 25faf38cb24d9ded4d29bac1d165b367edf96461 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 24 Sep 2018 00:32:49 +0200 Subject: [PATCH 228/247] =?UTF-8?q?Bump=20version:=201.8.6=20=E2=86=92=201?= =?UTF-8?q?.8.7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- ChangeLog | 8 ++++++++ version.py | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 539791f66..46c4514c3 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,4 +1,4 @@ [bumpversion] -current_version = 1.8.6 +current_version = 1.8.7 files = version.py diff --git a/ChangeLog b/ChangeLog index 230967669..061cbb26d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +================================================================ +Changes from Version 1.8.6 to 1.8.7 +! Bugfix: do not remove ASM blocks (optimize) + +================================================================ +Changes from Version 1.8.5 to 1.8.6 +! Bugfix: END instruction was not returning result. Fixed. + ================================================================ Changes from Version 1.8.4 to 1.8.5 ! Bugfix: crash on bad array declaration diff --git a/version.py b/version.py index 40c5bab5f..285c0d585 100755 --- a/version.py +++ b/version.py @@ -1 +1 @@ -VERSION = '1.8.6' +VERSION = '1.8.7' From 0503a2ae7b05626fd720f7dd27271f5b7dee77b5 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 30 Sep 2018 13:04:26 +0200 Subject: [PATCH 229/247] bugfix: 32bit operations bug Many 32 bit operations might fail (i.e. division) because the SWAP32 routine was buggy upon last optimization. Fixed. --- library-asm/swap32.asm | 8 +- tests/functional/divf16c.asm | 8 +- tests/functional/divi32c.asm | 8 +- tests/functional/divu32c.asm | 8 +- tests/functional/gef16.asm | 8 +- tests/functional/gei32.asm | 8 +- tests/functional/geu32.asm | 8 +- tests/functional/gtf16.asm | 8 +- tests/functional/gti32.asm | 8 +- tests/functional/gtu32.asm | 8 +- tests/functional/lef16.asm | 8 +- tests/functional/lei32.asm | 8 +- tests/functional/leu32.asm | 8 +- tests/functional/ltf16.asm | 8 +- tests/functional/lti32c.asm | 8 +- tests/functional/ltu32c.asm | 8 +- tests/functional/modf16c.asm | 8 +- tests/functional/modi32c.asm | 8 +- tests/functional/modu32c.asm | 8 +- tests/functional/subf16c.asm | 8 +- tests/functional/subi32c.asm | 8 +- tests/functional/subu32c.asm | 8 +- tests/functional/swap32.asm | 245 +++++++++++++++++++++++++++++++++++ tests/functional/swap32.bas | 4 + 24 files changed, 337 insertions(+), 88 deletions(-) create mode 100644 tests/functional/swap32.asm create mode 100644 tests/functional/swap32.bas diff --git a/library-asm/swap32.asm b/library-asm/swap32.asm index 56acde3f9..805bcf57e 100644 --- a/library-asm/swap32.asm +++ b/library-asm/swap32.asm @@ -4,13 +4,13 @@ __SWAP32: pop bc ; Return address ex (sp), hl - dec sp - dec sp + inc sp + inc sp ex de, hl ex (sp), hl ex de, hl - inc sp - inc sp + dec sp + dec sp push bc ret diff --git a/tests/functional/divf16c.asm b/tests/functional/divf16c.asm index fa311b530..fdd24169d 100644 --- a/tests/functional/divf16c.asm +++ b/tests/functional/divf16c.asm @@ -345,13 +345,13 @@ __ENDF16DIV: ; Put the sign on the result __SWAP32: pop bc ; Return address ex (sp), hl - dec sp - dec sp + inc sp + inc sp ex de, hl ex (sp), hl ex de, hl - inc sp - inc sp + dec sp + dec sp push bc ret diff --git a/tests/functional/divi32c.asm b/tests/functional/divi32c.asm index ba8085fcb..4ec3c1599 100644 --- a/tests/functional/divi32c.asm +++ b/tests/functional/divi32c.asm @@ -263,13 +263,13 @@ __MODI32: ; 32bits signed division modulus __SWAP32: pop bc ; Return address ex (sp), hl - dec sp - dec sp + inc sp + inc sp ex de, hl ex (sp), hl ex de, hl - inc sp - inc sp + dec sp + dec sp push bc ret diff --git a/tests/functional/divu32c.asm b/tests/functional/divu32c.asm index 18063a710..7403f96be 100644 --- a/tests/functional/divu32c.asm +++ b/tests/functional/divu32c.asm @@ -263,13 +263,13 @@ __MODI32: ; 32bits signed division modulus __SWAP32: pop bc ; Return address ex (sp), hl - dec sp - dec sp + inc sp + inc sp ex de, hl ex (sp), hl ex de, hl - inc sp - inc sp + dec sp + dec sp push bc ret diff --git a/tests/functional/gef16.asm b/tests/functional/gef16.asm index 315f9bb0d..54d9384c2 100644 --- a/tests/functional/gef16.asm +++ b/tests/functional/gef16.asm @@ -156,13 +156,13 @@ checkParity: __SWAP32: pop bc ; Return address ex (sp), hl - dec sp - dec sp + inc sp + inc sp ex de, hl ex (sp), hl ex de, hl - inc sp - inc sp + dec sp + dec sp push bc ret diff --git a/tests/functional/gei32.asm b/tests/functional/gei32.asm index 2dc95f04d..948c78e69 100644 --- a/tests/functional/gei32.asm +++ b/tests/functional/gei32.asm @@ -171,13 +171,13 @@ checkParity: __SWAP32: pop bc ; Return address ex (sp), hl - dec sp - dec sp + inc sp + inc sp ex de, hl ex (sp), hl ex de, hl - inc sp - inc sp + dec sp + dec sp push bc ret diff --git a/tests/functional/geu32.asm b/tests/functional/geu32.asm index 41302f58d..fac98f9d2 100644 --- a/tests/functional/geu32.asm +++ b/tests/functional/geu32.asm @@ -144,13 +144,13 @@ __SUB32: __SWAP32: pop bc ; Return address ex (sp), hl - dec sp - dec sp + inc sp + inc sp ex de, hl ex (sp), hl ex de, hl - inc sp - inc sp + dec sp + dec sp push bc ret diff --git a/tests/functional/gtf16.asm b/tests/functional/gtf16.asm index 280761f21..ba15764a1 100644 --- a/tests/functional/gtf16.asm +++ b/tests/functional/gtf16.asm @@ -165,13 +165,13 @@ checkParity: __SWAP32: pop bc ; Return address ex (sp), hl - dec sp - dec sp + inc sp + inc sp ex de, hl ex (sp), hl ex de, hl - inc sp - inc sp + dec sp + dec sp push bc ret diff --git a/tests/functional/gti32.asm b/tests/functional/gti32.asm index 69642c59d..255406949 100644 --- a/tests/functional/gti32.asm +++ b/tests/functional/gti32.asm @@ -180,13 +180,13 @@ checkParity: __SWAP32: pop bc ; Return address ex (sp), hl - dec sp - dec sp + inc sp + inc sp ex de, hl ex (sp), hl ex de, hl - inc sp - inc sp + dec sp + dec sp push bc ret diff --git a/tests/functional/gtu32.asm b/tests/functional/gtu32.asm index 644257340..a9ce2ad98 100644 --- a/tests/functional/gtu32.asm +++ b/tests/functional/gtu32.asm @@ -134,13 +134,13 @@ __CALL_BACK__: __SWAP32: pop bc ; Return address ex (sp), hl - dec sp - dec sp + inc sp + inc sp ex de, hl ex (sp), hl ex de, hl - inc sp - inc sp + dec sp + dec sp push bc ret diff --git a/tests/functional/lef16.asm b/tests/functional/lef16.asm index aec8174a2..b5db14f45 100644 --- a/tests/functional/lef16.asm +++ b/tests/functional/lef16.asm @@ -157,13 +157,13 @@ checkParity: __SWAP32: pop bc ; Return address ex (sp), hl - dec sp - dec sp + inc sp + inc sp ex de, hl ex (sp), hl ex de, hl - inc sp - inc sp + dec sp + dec sp push bc ret diff --git a/tests/functional/lei32.asm b/tests/functional/lei32.asm index 43ca35253..9ea97dc0b 100644 --- a/tests/functional/lei32.asm +++ b/tests/functional/lei32.asm @@ -170,13 +170,13 @@ checkParity: __SWAP32: pop bc ; Return address ex (sp), hl - dec sp - dec sp + inc sp + inc sp ex de, hl ex (sp), hl ex de, hl - inc sp - inc sp + dec sp + dec sp push bc ret diff --git a/tests/functional/leu32.asm b/tests/functional/leu32.asm index ec2ff13a4..9eba6f735 100644 --- a/tests/functional/leu32.asm +++ b/tests/functional/leu32.asm @@ -139,13 +139,13 @@ __CALL_BACK__: __SWAP32: pop bc ; Return address ex (sp), hl - dec sp - dec sp + inc sp + inc sp ex de, hl ex (sp), hl ex de, hl - inc sp - inc sp + dec sp + dec sp push bc ret diff --git a/tests/functional/ltf16.asm b/tests/functional/ltf16.asm index 4d2079315..dea2de2d5 100644 --- a/tests/functional/ltf16.asm +++ b/tests/functional/ltf16.asm @@ -148,13 +148,13 @@ checkParity: __SWAP32: pop bc ; Return address ex (sp), hl - dec sp - dec sp + inc sp + inc sp ex de, hl ex (sp), hl ex de, hl - inc sp - inc sp + dec sp + dec sp push bc ret diff --git a/tests/functional/lti32c.asm b/tests/functional/lti32c.asm index 0e4a27827..e2e640165 100644 --- a/tests/functional/lti32c.asm +++ b/tests/functional/lti32c.asm @@ -161,13 +161,13 @@ checkParity: __SWAP32: pop bc ; Return address ex (sp), hl - dec sp - dec sp + inc sp + inc sp ex de, hl ex (sp), hl ex de, hl - inc sp - inc sp + dec sp + dec sp push bc ret diff --git a/tests/functional/ltu32c.asm b/tests/functional/ltu32c.asm index 47fec8bcb..64355af68 100644 --- a/tests/functional/ltu32c.asm +++ b/tests/functional/ltu32c.asm @@ -139,13 +139,13 @@ __SUB32: __SWAP32: pop bc ; Return address ex (sp), hl - dec sp - dec sp + inc sp + inc sp ex de, hl ex (sp), hl ex de, hl - inc sp - inc sp + dec sp + dec sp push bc ret diff --git a/tests/functional/modf16c.asm b/tests/functional/modf16c.asm index 29c035267..6879491b6 100644 --- a/tests/functional/modf16c.asm +++ b/tests/functional/modf16c.asm @@ -496,13 +496,13 @@ __MODF16: __SWAP32: pop bc ; Return address ex (sp), hl - dec sp - dec sp + inc sp + inc sp ex de, hl ex (sp), hl ex de, hl - inc sp - inc sp + dec sp + dec sp push bc ret diff --git a/tests/functional/modi32c.asm b/tests/functional/modi32c.asm index e1ec47da1..590a049eb 100644 --- a/tests/functional/modi32c.asm +++ b/tests/functional/modi32c.asm @@ -263,13 +263,13 @@ __MODI32: ; 32bits signed division modulus __SWAP32: pop bc ; Return address ex (sp), hl - dec sp - dec sp + inc sp + inc sp ex de, hl ex (sp), hl ex de, hl - inc sp - inc sp + dec sp + dec sp push bc ret diff --git a/tests/functional/modu32c.asm b/tests/functional/modu32c.asm index b8d0f1cd0..0ddc43c2b 100644 --- a/tests/functional/modu32c.asm +++ b/tests/functional/modu32c.asm @@ -263,13 +263,13 @@ __MODI32: ; 32bits signed division modulus __SWAP32: pop bc ; Return address ex (sp), hl - dec sp - dec sp + inc sp + inc sp ex de, hl ex (sp), hl ex de, hl - inc sp - inc sp + dec sp + dec sp push bc ret diff --git a/tests/functional/subf16c.asm b/tests/functional/subf16c.asm index 7efa8c38a..b494f34c6 100644 --- a/tests/functional/subf16c.asm +++ b/tests/functional/subf16c.asm @@ -96,13 +96,13 @@ __SUB32: __SWAP32: pop bc ; Return address ex (sp), hl - dec sp - dec sp + inc sp + inc sp ex de, hl ex (sp), hl ex de, hl - inc sp - inc sp + dec sp + dec sp push bc ret diff --git a/tests/functional/subi32c.asm b/tests/functional/subi32c.asm index f30b79583..14fdf300e 100644 --- a/tests/functional/subi32c.asm +++ b/tests/functional/subi32c.asm @@ -105,13 +105,13 @@ __SUB32: __SWAP32: pop bc ; Return address ex (sp), hl - dec sp - dec sp + inc sp + inc sp ex de, hl ex (sp), hl ex de, hl - inc sp - inc sp + dec sp + dec sp push bc ret diff --git a/tests/functional/subu32c.asm b/tests/functional/subu32c.asm index 3c66baa6a..5de5e8617 100644 --- a/tests/functional/subu32c.asm +++ b/tests/functional/subu32c.asm @@ -105,13 +105,13 @@ __SUB32: __SWAP32: pop bc ; Return address ex (sp), hl - dec sp - dec sp + inc sp + inc sp ex de, hl ex (sp), hl ex de, hl - inc sp - inc sp + dec sp + dec sp push bc ret diff --git a/tests/functional/swap32.asm b/tests/functional/swap32.asm new file mode 100644 index 000000000..3e11789ce --- /dev/null +++ b/tests/functional/swap32.asm @@ -0,0 +1,245 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, (_a + 2) + push hl + ld hl, (_a) + push hl + ld de, 0 + ld hl, 10 + call __SWAP32 + call __DIVU32 + ld (_a), hl + ld (_a + 2), de + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "div32.asm" + +#line 1 "neg32.asm" + +__ABS32: + bit 7, d + ret z + +__NEG32: ; Negates DEHL (Two's complement) + ld a, l + cpl + ld l, a + + ld a, h + cpl + ld h, a + + ld a, e + cpl + ld e, a + + ld a, d + cpl + ld d, a + + inc l + ret nz + + inc h + ret nz + + inc de + ret + +#line 2 "div32.asm" + + ; --------------------------------------------------------- +__DIVU32: ; 32 bit unsigned division + ; DEHL = Dividend, Stack Top = Divisor + ; OPERANDS P = Dividend, Q = Divisor => OPERATION => P / Q + ; + ; Changes A, BC DE HL B'C' D'E' H'L' + ; --------------------------------------------------------- + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + +__DIVU32START: ; Performs D'E'H'L' / HLDE + ; Now switch to DIVIDEND = B'C'BC / DIVISOR = D'E'DE (A / B) + push de ; push Lowpart(Q) + ex de, hl ; DE = HL + ld hl, 0 + exx + ld b, h + ld c, l + pop hl + push de + ex de, hl + ld hl, 0 ; H'L'HL = 0 + exx + pop bc ; Pop HightPart(B) => B = B'C'BC + exx + + ld a, 32 ; Loop count + +__DIV32LOOP: + sll c ; B'C'BC << 1 ; Output most left bit to carry + rl b + exx + rl c + rl b + exx + + adc hl, hl + exx + adc hl, hl + exx + + sbc hl,de + exx + sbc hl,de + exx + jp nc, __DIV32NOADD ; use JP inside a loop for being faster + + add hl, de + exx + adc hl, de + exx + dec bc + +__DIV32NOADD: + dec a + jp nz, __DIV32LOOP ; use JP inside a loop for being faster + ; At this point, quotient is stored in B'C'BC and the reminder in H'L'HL + + push hl + exx + pop de + ex de, hl ; D'E'H'L' = 32 bits modulus + push bc + exx + pop de ; DE = B'C' + ld h, b + ld l, c ; DEHL = quotient D'E'H'L' = Modulus + + ret ; DEHL = quotient, D'E'H'L' = Modulus + + + +__MODU32: ; 32 bit modulus for 32bit unsigned division + ; DEHL = Dividend, Stack Top = Divisor (DE, HL) + + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + + call __DIVU32START ; At return, modulus is at D'E'H'L' + +__MODU32START: + + exx + push de + push hl + + exx + pop hl + pop de + + ret + + +__DIVI32: ; 32 bit signed division + ; DEHL = Dividend, Stack Top = Divisor + ; A = Dividend, B = Divisor => A / B + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + +__DIVI32START: + exx + ld a, d ; Save sign + ex af, af' + bit 7, d ; Negative? + call nz, __NEG32 ; Negates DEHL + + exx ; Now works with H'L'D'E' + ex af, af' + xor h + ex af, af' ; Stores sign of the result for later + + bit 7, h ; Negative? + ex de, hl ; HLDE = DEHL + call nz, __NEG32 + ex de, hl + + call __DIVU32START + ex af, af' ; Recovers sign + and 128 ; positive? + ret z + + jp __NEG32 ; Negates DEHL and returns from there + + +__MODI32: ; 32bits signed division modulus + exx + pop hl ; return address + pop de ; low part + ex (sp), hl ; CALLEE Convention ; H'L'D'E' => Dividend + + call __DIVI32START + jp __MODU32START + +#line 28 "swap32.bas" +#line 1 "swap32.asm" + + ; Exchanges current DE HL with the + ; ones in the stack + +__SWAP32: + pop bc ; Return address + ex (sp), hl + inc sp + inc sp + ex de, hl + ex (sp), hl + ex de, hl + dec sp + dec sp + push bc + ret + +#line 29 "swap32.bas" + +ZXBASIC_USER_DATA: +_a: + DEFB 0FFh + DEFB 0FFh + DEFB 00h + DEFB 00h + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/swap32.bas b/tests/functional/swap32.bas new file mode 100644 index 000000000..7388a29c6 --- /dev/null +++ b/tests/functional/swap32.bas @@ -0,0 +1,4 @@ +DIM a as ULong = 65535 + +LET a = a / 10 + From 23c809b745c39e48acd1f74ddd53d3403232ec13 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 30 Sep 2018 13:10:12 +0200 Subject: [PATCH 230/247] =?UTF-8?q?Bump=20version:=201.8.7=20=E2=86=92=201?= =?UTF-8?q?.8.8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- ChangeLog | 4 ++++ version.py | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 46c4514c3..d0decb5e0 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,4 +1,4 @@ [bumpversion] -current_version = 1.8.7 +current_version = 1.8.8 files = version.py diff --git a/ChangeLog b/ChangeLog index 061cbb26d..3c036768e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +================================================================ +Changes from Version 1.8.7 to 1.8.8 +! Bugfix: fix 32 bit operations (DIV, MOD...) + ================================================================ Changes from Version 1.8.6 to 1.8.7 ! Bugfix: do not remove ASM blocks (optimize) diff --git a/version.py b/version.py index 285c0d585..dfa1796c7 100755 --- a/version.py +++ b/version.py @@ -1 +1 @@ -VERSION = '1.8.7' +VERSION = '1.8.8' From c9b2322a6dc06a07c58be8ea4ed8510e16358e27 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 14 Oct 2018 20:12:49 +0200 Subject: [PATCH 231/247] add option --compile-only This cmd line option allows the compiler to parse and analyze the source code without emitting any code. --- tests/cmdline/__init__.py | 9 ++++++++ tests/cmdline/empty.bas | 2 ++ tests/cmdline/test_zxb.py | 44 +++++++++++++++++++++++++++++++++++++++ zxb.py | 9 +++++--- 4 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 tests/cmdline/__init__.py create mode 100644 tests/cmdline/empty.bas create mode 100644 tests/cmdline/test_zxb.py diff --git a/tests/cmdline/__init__.py b/tests/cmdline/__init__.py new file mode 100644 index 000000000..8a90b0f7c --- /dev/null +++ b/tests/cmdline/__init__.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import sys +import os +import os.path + +path = os.path.realpath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)) +sys.path.insert(0, path) diff --git a/tests/cmdline/empty.bas b/tests/cmdline/empty.bas new file mode 100644 index 000000000..139597f9c --- /dev/null +++ b/tests/cmdline/empty.bas @@ -0,0 +1,2 @@ + + diff --git a/tests/cmdline/test_zxb.py b/tests/cmdline/test_zxb.py new file mode 100644 index 000000000..807eae0fa --- /dev/null +++ b/tests/cmdline/test_zxb.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- + +import pytest +import zxb +import os + +PATH = os.path.realpath(os.path.dirname(os.path.abspath(__file__))) + + +class EnsureRemoveFile(object): + """ Ensures a filename is removed if exists after + a block of code is executed + """ + def __init__(self, output_file_name): + self.fname = output_file_name + + def remove_file(self): + if os.path.isfile(self.fname): + os.unlink(self.fname) + + def __enter__(self): + self.remove_file() + + def __exit__(self, exc_type, exc_val, exc_tb): + self.remove_file() + + +@pytest.fixture +def file_bas(): + return os.path.join(PATH, 'empty.bas') + + +@pytest.fixture +def file_bin(): + return os.path.join(PATH, 'empty.bin') + + +def test_compile_only(file_bas, file_bin): + """ Should not generate a file + """ + with EnsureRemoveFile(file_bin): + zxb.main(['--parse-only', file_bas, '-o', file_bin]) + assert not os.path.isfile(file_bin), 'Should not create file "empty.bin"' + diff --git a/zxb.py b/zxb.py index a49e97eff..f00ac18e0 100755 --- a/zxb.py +++ b/zxb.py @@ -144,6 +144,8 @@ def main(args=None): parser.add_argument('--headerless', action='store_true', help='Header-less mode: omit asm prologue and epilogue') parser.add_argument('--version', action='version', version='%(prog)s {0}'.format(VERSION)) + parser.add_argument('--compile-only', action='store_true', + help="Only compiles to check for syntax and semantic errors") options = parser.parse_args(args=args) @@ -187,8 +189,9 @@ def main(args=None): debug.ENABLED = OPTIONS.Debug.value - if int(options.tzx) + int(options.tap) + int(options.asm) + int(options.emit_backend) > 1: - parser.error("Options --tap, --tzx, --emit-backend and --asm are mutually exclusive") + if int(options.tzx) + int(options.tap) + int(options.asm) + int(options.emit_backend) + \ + int(options.compile_only) > 1: + parser.error("Options --tap, --tzx, --emit-backend, --compile-only and --asm are mutually exclusive") return 3 if options.basic and not options.tzx and not options.tap: @@ -319,7 +322,7 @@ def main(args=None): if options.asm: # Only output assembler file with open_file(OPTIONS.outputFileName.value, 'wt', 'utf-8') as output_file: output(asm_output, output_file) - else: + elif not options.compile_only: fout = StringIO() output(asm_output, fout) asmparse.assemble(fout.getvalue()) From 0e1b501a8729586b40ac6b48058fb630e767e56e Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 21 Oct 2018 17:52:45 +0200 Subject: [PATCH 232/247] feature: allow specifying ORG in hexa This will allow to invoke zxb with --org=0xC000 for example. --- api/utils.py | 28 ++++++++++++++++++++++++++++ tests/cmdline/test_zxb.py | 7 +++++++ tests/functional/test_.py | 7 +++++-- zxb.py | 17 ++++++++++------- 4 files changed, 50 insertions(+), 9 deletions(-) diff --git a/api/utils.py b/api/utils.py index b33cd04bb..160eec775 100644 --- a/api/utils.py +++ b/api/utils.py @@ -72,3 +72,31 @@ def flatten_list(x): result.extend(flatten_list(l)) return result + + +def parse_int(str_num): + """ Given an integer number, return its value, + or None if it could not be parsed. + Allowed formats: DECIMAL, HEXA (0xnnn, $nnnn or nnnnh) + :param str_num: (string) the number to be parsed + :return: an integer number or None if it could not be parsedd + """ + str_num = (str_num or "").strip().upper() + if not str_num: + return None + + base = 10 + if str_num.startswith('0X'): + base = 16 + str_num = str_num[2:] + if str_num.endswith('H'): + base = 16 + str_num = str_num[:-1] + if str_num.startswith('$'): + base = 16 + str_num = str_num[1:] + + try: + return int(str_num, base) + except ValueError: + return None diff --git a/tests/cmdline/test_zxb.py b/tests/cmdline/test_zxb.py index 807eae0fa..e57935f0a 100644 --- a/tests/cmdline/test_zxb.py +++ b/tests/cmdline/test_zxb.py @@ -42,3 +42,10 @@ def test_compile_only(file_bas, file_bin): zxb.main(['--parse-only', file_bas, '-o', file_bin]) assert not os.path.isfile(file_bin), 'Should not create file "empty.bin"' + +def test_org_allows_0xnnnn_format(file_bas, file_bin): + """ Should allow hexadecimal format 0x in org + """ + with EnsureRemoveFile(file_bin): + zxb.main(['--parse-only', '--org', '0xC000', file_bas, '-o', file_bin]) + assert zxb.OPTIONS.org.value == 0xC000, 'Should set ORG to 0xC000' diff --git a/tests/functional/test_.py b/tests/functional/test_.py index c3edb13ac..270d9400c 100755 --- a/tests/functional/test_.py +++ b/tests/functional/test_.py @@ -19,7 +19,10 @@ def flush(self): sys.stdout.flush() -def process_file(fname): +def process_file(fname, params=None): + if params is None: + params = ['-S', '-q'] + try: current_path = os.path.abspath(os.getcwd()) test.set_temp_dir() @@ -29,7 +32,7 @@ def process_file(fname): fname = os.path.basename(fname) else: os.chdir(os.path.realpath(os.path.dirname(__file__))) - test.main(['-S', '-q', fname]) + test.main(params + [fname]) os.chdir(current_path) finally: os.rmdir(test.TEMP_DIR) diff --git a/zxb.py b/zxb.py index f00ac18e0..f57809685 100755 --- a/zxb.py +++ b/zxb.py @@ -106,7 +106,7 @@ def main(args=None): help="Sets the program to be run once loaded") parser.add_argument('-A', '--asm', action='store_true', help="Sets output format to asm") - parser.add_argument('-S', '--org', type=int, default=OPTIONS.org.value, + parser.add_argument('-S', '--org', type=str, default=str(OPTIONS.org.value), help="Start of machine code. By default %i" % OPTIONS.org.value) parser.add_argument('-e', '--errmsg', type=str, dest='stderr', default=OPTIONS.StdErrFileName.value, help='Error messages file (standard error console by default)') @@ -144,8 +144,8 @@ def main(args=None): parser.add_argument('--headerless', action='store_true', help='Header-less mode: omit asm prologue and epilogue') parser.add_argument('--version', action='version', version='%(prog)s {0}'.format(VERSION)) - parser.add_argument('--compile-only', action='store_true', - help="Only compiles to check for syntax and semantic errors") + parser.add_argument('--parse-only', action='store_true', + help="Only parses to check for syntax and semantic errors") options = parser.parse_args(args=args) @@ -160,7 +160,6 @@ def main(args=None): OPTIONS.array_base.value = options.array_base OPTIONS.string_base.value = options.string_base OPTIONS.Sinclair.value = options.sinclair - OPTIONS.org.value = options.org OPTIONS.heap_size.value = options.heap_size OPTIONS.memoryCheck.value = options.debug_memory OPTIONS.strictBool.value = options.strict_bool or OPTIONS.Sinclair.value @@ -172,6 +171,10 @@ def main(args=None): OPTIONS.strict.value = options.strict OPTIONS.headerless.value = options.headerless + OPTIONS.org.value = api.utils.parse_int(options.org) + if OPTIONS.org.value is None: + parser.error("Invalid --org option '{}'".format(options.org)) + if options.defines: for i in options.defines: name, val = tuple(i.split('=', 1)) @@ -190,8 +193,8 @@ def main(args=None): debug.ENABLED = OPTIONS.Debug.value if int(options.tzx) + int(options.tap) + int(options.asm) + int(options.emit_backend) + \ - int(options.compile_only) > 1: - parser.error("Options --tap, --tzx, --emit-backend, --compile-only and --asm are mutually exclusive") + int(options.parse_only) > 1: + parser.error("Options --tap, --tzx, --emit-backend, --parse-only and --asm are mutually exclusive") return 3 if options.basic and not options.tzx and not options.tap: @@ -322,7 +325,7 @@ def main(args=None): if options.asm: # Only output assembler file with open_file(OPTIONS.outputFileName.value, 'wt', 'utf-8') as output_file: output(asm_output, output_file) - elif not options.compile_only: + elif not options.parse_only: fout = StringIO() output(asm_output, fout) asmparse.assemble(fout.getvalue()) From b48bef523b52b10bcefab0838e3b0fca86a4f4b5 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 14 Nov 2018 00:47:00 +0100 Subject: [PATCH 233/247] bugfix: crash upon constant array access Defining a var like DIM p = @a(3, 4) being var a an array crashed the compiler. Fixed. --- arch/zx48k/translator.py | 3 ++ tests/functional/arrconst.asm | 61 +++++++++++++++++++++++++++++++++++ tests/functional/arrconst.bas | 5 +++ 3 files changed, 69 insertions(+) create mode 100644 tests/functional/arrconst.asm create mode 100644 tests/functional/arrconst.bas diff --git a/arch/zx48k/translator.py b/arch/zx48k/translator.py index be043866a..32808d716 100644 --- a/arch/zx48k/translator.py +++ b/arch/zx48k/translator.py @@ -285,6 +285,9 @@ def traverse_const(node): if node.token == 'CONST': return Translator.traverse_const(node.expr) + if node.token == 'ARRAYACCESS': + return '({} + {})'.format(node.entry.mangled, node.offset) + raise InvalidCONSTexpr(node) @staticmethod diff --git a/tests/functional/arrconst.asm b/tests/functional/arrconst.asm new file mode 100644 index 000000000..3f0ee8e83 --- /dev/null +++ b/tests/functional/arrconst.asm @@ -0,0 +1,61 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, (_p) + ld (_p), hl + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 + +ZXBASIC_USER_DATA: +_p: + DEFW (_a + 5) +_a: + DEFW 0001h + DEFW 0003h + DEFB 02h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/arrconst.bas b/tests/functional/arrconst.bas new file mode 100644 index 000000000..daa169f44 --- /dev/null +++ b/tests/functional/arrconst.bas @@ -0,0 +1,5 @@ + +DIM a(2, 2) as UInteger +DIM p = @a(0, 0) +p = p + From efd3020a7c1a3590243ec71e4a0a878d5e49e408 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 14 Nov 2018 00:56:15 +0100 Subject: [PATCH 234/247] Add runtime test arrcheck2 for array testing This one checks the array element position is correctly computed (chained multiplication). --- tests/runtime/arrcheck2.bas | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 tests/runtime/arrcheck2.bas diff --git a/tests/runtime/arrcheck2.bas b/tests/runtime/arrcheck2.bas new file mode 100644 index 000000000..3bb2b033b --- /dev/null +++ b/tests/runtime/arrcheck2.bas @@ -0,0 +1,24 @@ + +DIM a(7, 19, 11) as UInteger +DIM p = @a(0, 0, 0) +DIM i as Uinteger +DIM j as UInteger +DIM k as UInteger +DIM m as UInteger + +FOR i = 0 TO 7 + FOR j = 0 TO 19 + FOR k = 0 TO 11 + LET m = i * j * k + LET a(i, j, k) = m + PRINT AT 0, 0; i; " "; j; " "; k; " " + IF PEEK(UInteger, p) <> m THEN + PRINT INK 2; FLASH 1; " ERROR " + STOP + END IF + LET p = p + 2 + NEXT k + NEXT j +NEXT i + +PRINT INK 4; FLASH 1; " OK " From 910c87efb061b21cd2fdf27ff06f26bb20729919 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 14 Nov 2018 00:57:33 +0100 Subject: [PATCH 235/247] Bugfix: fix debug array check not working The flag --debug-array emited wrong code. The Array calculation routine has been optimized (a little) and now does the check correctly. Also de translator was not correctly emiting the IC. --- arch/zx48k/translator.py | 13 +++++-------- library-asm/array.asm | 10 +--------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/arch/zx48k/translator.py b/arch/zx48k/translator.py index 32808d716..90467f4bc 100644 --- a/arch/zx48k/translator.py +++ b/arch/zx48k/translator.py @@ -460,6 +460,11 @@ def visit_ARGLIST(self, node): for i in range(len(node) - 1, -1, -1): # visit in reverse order yield node[i] + if isinstance(node.parent, symbols.ARRAYACCESS) and OPTIONS.arrayCheck.value: + upper = node.parent.entry.bounds[i].upper + lower = node.parent.entry.bounds[i].lower + self.emit('paramu16', upper - lower) + def visit_ARGUMENT(self, node): if not node.byref: suffix = self.TSUFFIX(node.type_) @@ -499,11 +504,6 @@ def visit_ARRAYLOAD(self, node): if node.offset is None: yield node.args - if OPTIONS.arrayCheck.value: - upper = node.entry.bounds[0].upper - lower = node.entry.bounds[0].lower - self.emit('paramu16', upper - lower) - if scope == SCOPE.global_: self.emit('aload' + self.TSUFFIX(node.type_), node.entry.t, node.entry.mangled) elif scope == SCOPE.parameter: @@ -647,9 +647,6 @@ def visit_LETARRAYSUBSTR(self, node): def visit_ARRAYACCESS(self, node): yield node.arglist - if OPTIONS.arrayCheck.value: - self.emit('param' + self.TSUFFIX(gl.BOUND_TYPE), len(node.entry.bounds)) - def visit_STRSLICE(self, node): yield node.string if node.string.token == 'STRING' or \ diff --git a/library-asm/array.asm b/library-asm/array.asm index c5c4ff696..b2d185e6f 100644 --- a/library-asm/array.asm +++ b/library-asm/array.asm @@ -42,11 +42,10 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" +LOOP: #ifdef __CHECK_ARRAY_BOUNDARY__ pop de #endif - -LOOP: pop bc ; Get next index (Ai) from the stack #ifdef __CHECK_ARRAY_BOUNDARY__ @@ -74,15 +73,8 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#ifdef __CHECK_ARRAY_BOUNDARY__ - push de -#endif ;call __MUL16_FAST ; HL *= DE call __FNMUL -#ifdef __CHECK_ARRAY_BOUNDARY__ - pop de - dec de -#endif jp LOOP ARRAY_END: From 248bc7de20efe546d0871a6de60f4faddce1a18a Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Thu, 15 Nov 2018 00:00:10 +0100 Subject: [PATCH 236/247] Update tests --- tests/functional/46.asm | 11 ++++------- tests/functional/47.asm | 11 ++++------- tests/functional/55.asm | 11 ++++------- tests/functional/aloadstr1.asm | 11 ++++------- tests/functional/array03.asm | 11 ++++------- tests/functional/array06.asm | 11 ++++------- tests/functional/array07.asm | 11 ++++------- tests/functional/array08.asm | 11 ++++------- tests/functional/array09.asm | 11 ++++------- tests/functional/array10.asm | 11 ++++------- tests/functional/array12.asm | 11 ++++------- tests/functional/astore16.asm | 11 ++++------- tests/functional/let_array_substr.asm | 11 ++++------- tests/functional/let_array_substr1.asm | 11 ++++------- tests/functional/let_array_substr5.asm | 11 ++++------- tests/functional/ltee10.asm | 11 ++++------- tests/functional/ltee6.asm | 11 ++++------- tests/functional/ltee7.asm | 11 ++++------- tests/functional/opt2_snake_es.asm | 11 ++++------- tests/functional/opt3_OPT27wws2.asm | 11 ++++------- tests/functional/opt3_data2.asm | 11 ++++------- tests/functional/read9.asm | 11 ++++------- 22 files changed, 88 insertions(+), 154 deletions(-) diff --git a/tests/functional/46.asm b/tests/functional/46.asm index ca025a8d4..e3cbf2ca8 100644 --- a/tests/functional/46.asm +++ b/tests/functional/46.asm @@ -140,12 +140,11 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/src/zxb/trunk/library-asm/array.asm" - LOOP: +#line 49 "/src/zxb/trunk/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 60 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -163,10 +162,8 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -177,7 +174,7 @@ ARRAY_END: push de exx -#line 100 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -208,7 +205,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/47.asm b/tests/functional/47.asm index 1f517ec29..b4857103f 100644 --- a/tests/functional/47.asm +++ b/tests/functional/47.asm @@ -167,12 +167,11 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/src/zxb/trunk/library-asm/array.asm" - LOOP: +#line 49 "/src/zxb/trunk/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 60 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -190,10 +189,8 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -204,7 +201,7 @@ ARRAY_END: push de exx -#line 100 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -235,7 +232,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/55.asm b/tests/functional/55.asm index 189e202bb..b75d4ec38 100644 --- a/tests/functional/55.asm +++ b/tests/functional/55.asm @@ -135,12 +135,11 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/src/zxb/trunk/library-asm/array.asm" - LOOP: +#line 49 "/src/zxb/trunk/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 60 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -158,10 +157,8 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -172,7 +169,7 @@ ARRAY_END: push de exx -#line 100 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -203,7 +200,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/aloadstr1.asm b/tests/functional/aloadstr1.asm index 9507c722b..ebacf0849 100644 --- a/tests/functional/aloadstr1.asm +++ b/tests/functional/aloadstr1.asm @@ -138,12 +138,11 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/src/zxb/trunk/library-asm/array.asm" - LOOP: +#line 49 "/src/zxb/trunk/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 60 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -161,10 +160,8 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -175,7 +172,7 @@ ARRAY_END: push de exx -#line 100 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -206,7 +203,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/array03.asm b/tests/functional/array03.asm index 630631c9a..ca70f21ce 100644 --- a/tests/functional/array03.asm +++ b/tests/functional/array03.asm @@ -133,12 +133,11 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/src/zxb/trunk/library-asm/array.asm" - LOOP: +#line 49 "/src/zxb/trunk/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 60 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -156,10 +155,8 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -170,7 +167,7 @@ ARRAY_END: push de exx -#line 100 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -201,7 +198,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/array06.asm b/tests/functional/array06.asm index d4ddedce3..b6fc12f28 100644 --- a/tests/functional/array06.asm +++ b/tests/functional/array06.asm @@ -133,12 +133,11 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/src/zxb/trunk/library-asm/array.asm" - LOOP: +#line 49 "/src/zxb/trunk/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 60 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -156,10 +155,8 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -170,7 +167,7 @@ ARRAY_END: push de exx -#line 100 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -201,7 +198,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/array07.asm b/tests/functional/array07.asm index d8aeb3612..774a4bc51 100644 --- a/tests/functional/array07.asm +++ b/tests/functional/array07.asm @@ -156,12 +156,11 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/src/zxb/trunk/library-asm/array.asm" - LOOP: +#line 49 "/src/zxb/trunk/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 60 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -179,10 +178,8 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -193,7 +190,7 @@ ARRAY_END: push de exx -#line 100 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -224,7 +221,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/array08.asm b/tests/functional/array08.asm index 11d22cf91..174c4493e 100644 --- a/tests/functional/array08.asm +++ b/tests/functional/array08.asm @@ -134,12 +134,11 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/src/zxb/trunk/library-asm/array.asm" - LOOP: +#line 49 "/src/zxb/trunk/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 60 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -157,10 +156,8 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -171,7 +168,7 @@ ARRAY_END: push de exx -#line 100 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -202,7 +199,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/array09.asm b/tests/functional/array09.asm index 778c07563..9dd88c40b 100644 --- a/tests/functional/array09.asm +++ b/tests/functional/array09.asm @@ -134,12 +134,11 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/src/zxb/trunk/library-asm/array.asm" - LOOP: +#line 49 "/src/zxb/trunk/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 60 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -157,10 +156,8 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -171,7 +168,7 @@ ARRAY_END: push de exx -#line 100 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -202,7 +199,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/array10.asm b/tests/functional/array10.asm index b4575b4de..8d6f2b0e0 100644 --- a/tests/functional/array10.asm +++ b/tests/functional/array10.asm @@ -166,12 +166,11 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/src/zxb/trunk/library-asm/array.asm" - LOOP: +#line 49 "/src/zxb/trunk/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 60 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -189,10 +188,8 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -203,7 +200,7 @@ ARRAY_END: push de exx -#line 100 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -234,7 +231,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/array12.asm b/tests/functional/array12.asm index 70da58a5f..42a760e67 100644 --- a/tests/functional/array12.asm +++ b/tests/functional/array12.asm @@ -136,12 +136,11 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/src/zxb/trunk/library-asm/array.asm" - LOOP: +#line 49 "/src/zxb/trunk/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 60 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -159,10 +158,8 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -173,7 +170,7 @@ ARRAY_END: push de exx -#line 100 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -204,7 +201,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/astore16.asm b/tests/functional/astore16.asm index 3c59a2cbb..eab6b4224 100644 --- a/tests/functional/astore16.asm +++ b/tests/functional/astore16.asm @@ -160,12 +160,11 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/src/zxb/trunk/library-asm/array.asm" - LOOP: +#line 49 "/src/zxb/trunk/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 60 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -183,10 +182,8 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -197,7 +194,7 @@ ARRAY_END: push de exx -#line 100 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -228,7 +225,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/let_array_substr.asm b/tests/functional/let_array_substr.asm index 9e1d270c3..8e3fdb996 100644 --- a/tests/functional/let_array_substr.asm +++ b/tests/functional/let_array_substr.asm @@ -171,12 +171,11 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/src/zxb/trunk/library-asm/array.asm" - LOOP: +#line 49 "/src/zxb/trunk/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 60 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -194,10 +193,8 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -208,7 +205,7 @@ ARRAY_END: push de exx -#line 100 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -239,7 +236,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/let_array_substr1.asm b/tests/functional/let_array_substr1.asm index eb062d890..a8df9e06d 100644 --- a/tests/functional/let_array_substr1.asm +++ b/tests/functional/let_array_substr1.asm @@ -171,12 +171,11 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/src/zxb/trunk/library-asm/array.asm" - LOOP: +#line 49 "/src/zxb/trunk/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 60 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -194,10 +193,8 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -208,7 +205,7 @@ ARRAY_END: push de exx -#line 100 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -239,7 +236,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/let_array_substr5.asm b/tests/functional/let_array_substr5.asm index 224ac4e01..a3a06a424 100644 --- a/tests/functional/let_array_substr5.asm +++ b/tests/functional/let_array_substr5.asm @@ -171,12 +171,11 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/src/zxb/trunk/library-asm/array.asm" - LOOP: +#line 49 "/src/zxb/trunk/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 60 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -194,10 +193,8 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -208,7 +205,7 @@ ARRAY_END: push de exx -#line 100 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -239,7 +236,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/ltee10.asm b/tests/functional/ltee10.asm index cd6491273..e9315333a 100644 --- a/tests/functional/ltee10.asm +++ b/tests/functional/ltee10.asm @@ -155,12 +155,11 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/src/zxb/trunk/library-asm/array.asm" - LOOP: +#line 49 "/src/zxb/trunk/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 60 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -178,10 +177,8 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -192,7 +189,7 @@ ARRAY_END: push de exx -#line 100 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -223,7 +220,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/ltee6.asm b/tests/functional/ltee6.asm index ef574d011..74c44c58d 100644 --- a/tests/functional/ltee6.asm +++ b/tests/functional/ltee6.asm @@ -144,12 +144,11 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/src/zxb/trunk/library-asm/array.asm" - LOOP: +#line 49 "/src/zxb/trunk/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 60 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -167,10 +166,8 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -181,7 +178,7 @@ ARRAY_END: push de exx -#line 100 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -212,7 +209,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/ltee7.asm b/tests/functional/ltee7.asm index 6d0651ee2..a48906068 100644 --- a/tests/functional/ltee7.asm +++ b/tests/functional/ltee7.asm @@ -182,12 +182,11 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/src/zxb/trunk/library-asm/array.asm" - LOOP: +#line 49 "/src/zxb/trunk/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 60 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -205,10 +204,8 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -219,7 +216,7 @@ ARRAY_END: push de exx -#line 100 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -250,7 +247,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/opt2_snake_es.asm b/tests/functional/opt2_snake_es.asm index 5540c63da..d403db9fc 100644 --- a/tests/functional/opt2_snake_es.asm +++ b/tests/functional/opt2_snake_es.asm @@ -141,12 +141,11 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/src/zxb/trunk/library-asm/array.asm" - LOOP: +#line 49 "/src/zxb/trunk/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 60 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -164,10 +163,8 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -178,7 +175,7 @@ ARRAY_END: push de exx -#line 100 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -209,7 +206,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/opt3_OPT27wws2.asm b/tests/functional/opt3_OPT27wws2.asm index f1eea3a4a..d80751e05 100644 --- a/tests/functional/opt3_OPT27wws2.asm +++ b/tests/functional/opt3_OPT27wws2.asm @@ -142,12 +142,11 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/src/zxb/trunk/library-asm/array.asm" - LOOP: +#line 49 "/src/zxb/trunk/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 60 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -165,10 +164,8 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -179,7 +176,7 @@ ARRAY_END: push de exx -#line 100 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -210,7 +207,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/opt3_data2.asm b/tests/functional/opt3_data2.asm index fb20c2605..71b41a3e7 100644 --- a/tests/functional/opt3_data2.asm +++ b/tests/functional/opt3_data2.asm @@ -208,12 +208,11 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/src/zxb/trunk/library-asm/array.asm" - LOOP: +#line 49 "/src/zxb/trunk/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 60 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -231,10 +230,8 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -245,7 +242,7 @@ ARRAY_END: push de exx -#line 100 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -276,7 +273,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start diff --git a/tests/functional/read9.asm b/tests/functional/read9.asm index 1c154dff7..043aa4b28 100644 --- a/tests/functional/read9.asm +++ b/tests/functional/read9.asm @@ -230,12 +230,11 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" -#line 48 "/src/zxb/trunk/library-asm/array.asm" - LOOP: +#line 49 "/src/zxb/trunk/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 60 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/src/zxb/trunk/library-asm/array.asm" add hl, bc ; Adds current index @@ -253,10 +252,8 @@ LOOP: exx pop de ; DE = Max bound Number (i-th dimension) -#line 80 "/src/zxb/trunk/library-asm/array.asm" ;call __MUL16_FAST ; HL *= DE call __FNMUL -#line 86 "/src/zxb/trunk/library-asm/array.asm" jp LOOP ARRAY_END: @@ -267,7 +264,7 @@ ARRAY_END: push de exx -#line 100 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/src/zxb/trunk/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -298,7 +295,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 131 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/src/zxb/trunk/library-asm/array.asm" pop de add hl, de ; Adds element start From 78330163fad2575cce72ca2242d86d7b34f228ed Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Thu, 15 Nov 2018 00:00:28 +0100 Subject: [PATCH 237/247] Update flake8 tests --- arch/zx48k/backend/__init__.py | 2 +- arch/zx48k/optimizer.py | 10 +++++----- tox.ini | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/zx48k/backend/__init__.py b/arch/zx48k/backend/__init__.py index 0ed3d67e1..e3330818d 100644 --- a/arch/zx48k/backend/__init__.py +++ b/arch/zx48k/backend/__init__.py @@ -132,7 +132,7 @@ OPT32 = True # Label RegExp -RE_LABEL = re.compile('^[ \t]*[a-zA-Z_][_a-zA-Z\d]*:') +RE_LABEL = re.compile(r'^[ \t]*[a-zA-Z_][_a-zA-Z\d]*:') # (ix +/- ...) regexp RE_IX_IDX = re.compile(r'^\([ \t]*ix[ \t]*[-+][ \t]*.+\)$') diff --git a/arch/zx48k/optimizer.py b/arch/zx48k/optimizer.py index 8beedb11a..cf0b68e7a 100644 --- a/arch/zx48k/optimizer.py +++ b/arch/zx48k/optimizer.py @@ -44,14 +44,14 @@ 'bc', 'de', 'hl', 'sp', 'ix', 'iy', 'ixh', 'ixl', 'iyh', 'iyl', 'af', "af'", 'i', 'r'} -RE_NUMBER = re.compile('^([-+]?[0-9]+|$[A-Fa-f0-9]+|[0-9][A-Fa-f0-9]*[Hh]|%[01]+|[01]+[bB])$') +RE_NUMBER = re.compile(r'^([-+]?[0-9]+|$[A-Fa-f0-9]+|[0-9][A-Fa-f0-9]*[Hh]|%[01]+|[01]+[bB])$') RE_INDIR = re.compile(r'\([ \t]*[Ii][XxYy][ \t]*[-+][ \t]*[0-9]+[ \t]*\)') RE_IXIND = re.compile(r'[iI][xXyY]([-+][0-9]+)?') RE_LABEL = re.compile(r'^[ \t]*[_a-zA-Z][a-zA-Z\d]*:') -RE_INDIR16 = re.compile('r[ \t]*\([ \t]*([dD][eE])|([hH][lL])[ \t]*\)[ \t]*') -RE_OUTC = re.compile('[ \t]*\([ \t]*[cC]\)') -RE_ID = re.compile('[.a-zA-Z_][.a-zA-Z_0-9]*') -RE_PRAGMA = re.compile('^#[ \t]?pragma[ \t]opt[ \t]') +RE_INDIR16 = re.compile(r'[ \t]*\([ \t]*([dD][eE])|([hH][lL])[ \t]*\)[ \t]*') +RE_OUTC = re.compile(r'[ \t]*\([ \t]*[cC]\)') +RE_ID = re.compile(r'[.a-zA-Z_][.a-zA-Z_0-9]*') +RE_PRAGMA = re.compile(r'^#[ \t]?pragma[ \t]opt[ \t]') # Enabled Optimizations (this is useful for debugging) OPT00 = True diff --git a/tox.ini b/tox.ini index 4e1fffb00..25707ddd7 100644 --- a/tox.ini +++ b/tox.ini @@ -16,7 +16,7 @@ commands = [flake8] max-line-length = 120 -ignore = E722, E731, E741 +ignore = E722, E731, E741, W504 exclude = .cache/, .tox/, From e5694195aea07e5d2a069bc358e49a8f97c7696b Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Thu, 15 Nov 2018 01:01:39 +0100 Subject: [PATCH 238/247] add test to check for array boundary checking Note that both #pragma and #define must be used since the array checking requires such define that might not be declared at the beginning. --- tests/functional/arrcheck.asm | 389 ++++++++++++++++++++++++++++++++++ tests/functional/arrcheck.bas | 10 + 2 files changed, 399 insertions(+) create mode 100644 tests/functional/arrcheck.asm create mode 100644 tests/functional/arrcheck.bas diff --git a/tests/functional/arrcheck.asm b/tests/functional/arrcheck.asm new file mode 100644 index 000000000..d1fae43e2 --- /dev/null +++ b/tests/functional/arrcheck.asm @@ -0,0 +1,389 @@ + org 32768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + ld hl, (_b) + push hl + ld hl, 5 + push hl + ld hl, (_b) + push hl + ld hl, 10 + push hl + ld hl, _a + call __ARRAY + ld (hl), 7 + ld hl, (_b) + push hl + ld hl, 5 + push hl + ld hl, (_b) + ld de, 6 + add hl, de + push hl + ld hl, 10 + push hl + ld hl, _a + call __ARRAY + ld a, (hl) + ld (_c), a + ld (_c), a + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +#line 1 "array.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; ------------------------------------------------------------------- + ; Simple array Index routine + ; Number of total indexes dimensions - 1 at beginning of memory + ; HL = Start of array memory (First two bytes contains N-1 dimensions) + ; Dimension values on the stack, (top of the stack, highest dimension) + ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> + + ; For any array of N dimension A(aN-1, ..., a1, a0) + ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as + ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] +; What I will do here is to calculate the following sequence: + ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... + + +#line 1 "mul16.asm" + +__MUL16: ; Mutiplies HL with the last value stored into de stack + ; Works for both signed and unsigned + + PROC + + LOCAL __MUL16LOOP + LOCAL __MUL16NOADD + + ex de, hl + pop hl ; Return address + ex (sp), hl ; CALLEE caller convention + +;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand + ;; ld c, h + ;; ld a, l ; C,A => 1st Operand + ;; + ;; ld hl, 0 ; Accumulator + ;; ld b, 16 + ;; +;;__MUL16LOOP: + ;; sra c ; C,A >> 1 (Arithmetic) + ;; rra + ;; + ;; jr nc, __MUL16NOADD + ;; add hl, de + ;; +;;__MUL16NOADD: + ;; sla e + ;; rl d + ;; + ;; djnz __MUL16LOOP + +__MUL16_FAST: + ld b, 16 + ld a, d + ld c, e + ex de, hl + ld hl, 0 + +__MUL16LOOP: + add hl, hl ; hl << 1 + sla c + rla ; a,c << 1 + jp nc, __MUL16NOADD + add hl, de + +__MUL16NOADD: + djnz __MUL16LOOP + + ret ; Result in hl (16 lower bits) + + ENDP + +#line 20 "array.asm" + + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 23 "array.asm" +#line 24 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/array.asm" + +__ARRAY: + PROC + + LOCAL LOOP + LOCAL ARRAY_END + LOCAL RET_ADDRESS ; Stores return address + + ex (sp), hl ; Return address in HL, array address in the stack + ld (RET_ADDRESS + 1), hl ; Stores it for later + + exx + pop hl ; Will use H'L' as the pointer + ld c, (hl) ; Loads Number of dimensions from (hl) + inc hl + ld b, (hl) + inc hl ; Ready + exx + + ld hl, 0 ; BC = Offset "accumulator" + +LOOP: + + pop de +#line 49 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/array.asm" + pop bc ; Get next index (Ai) from the stack + + + ex de, hl + or a + sbc hl, bc + ld a, ERROR_SubscriptWrong + jp c, __ERROR + ex de, hl +#line 59 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/array.asm" + + add hl, bc ; Adds current index + + exx ; Checks if B'C' = 0 + ld a, b ; Which means we must exit (last element is not multiplied by anything) + or c + jr z, ARRAY_END ; if B'Ci == 0 we are done + + ld e, (hl) ; Loads next dimension into D'E' + inc hl + ld d, (hl) + inc hl + push de + dec bc ; Decrements loop counter + exx + pop de ; DE = Max bound Number (i-th dimension) + + ;call __MUL16_FAST ; HL *= DE + call __FNMUL + jp LOOP + +ARRAY_END: + ld e, (hl) + inc hl + ld d, c ; C = 0 => DE = E = Element size + push hl + push de + exx + +#line 92 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/array.asm" + LOCAL ARRAY_SIZE_LOOP + + ex de, hl + ld hl, 0 + pop bc + ld b, c +ARRAY_SIZE_LOOP: + add hl, de + djnz ARRAY_SIZE_LOOP + + ;; Even faster + ;pop bc + + ;ld d, h + ;ld e, l + + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, hl + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, hl + ;dec c + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, de + ;__ARRAY_FIN: +#line 123 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/array.asm" + + pop de + add hl, de ; Adds element start + +RET_ADDRESS: + ld de, 0 + push de + ret ; HL = (Start of Elements + Offset) + + ;; Performs a faster multiply for little 16bit numbs + LOCAL __FNMUL, __FNMUL2 + +__FNMUL: + xor a + or d + jp nz, __MUL16_FAST + + or e + ex de, hl + ret z + + cp 33 + jp nc, __MUL16_FAST + + ld b, l + ld l, h ; HL = 0 + +__FNMUL2: + add hl, de + djnz __FNMUL2 + ret + + ENDP + +#line 44 "arrcheck.bas" + +ZXBASIC_USER_DATA: +_c: + DEFB 00 +_b: + DEFB 05h + DEFB 00h +_a: + DEFW 0001h + DEFW 0006h + DEFB 01h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + ; Defines DATA END --> HEAP size is 0 +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/arrcheck.bas b/tests/functional/arrcheck.bas new file mode 100644 index 000000000..51f503a9a --- /dev/null +++ b/tests/functional/arrcheck.bas @@ -0,0 +1,10 @@ +#pragma arrayCheck=true +#define __CHECK_ARRAY_BOUNDARY__ + +DIM a(10, 5) as byte +DIM c as Byte + +DIM b as UInteger = 5 +Let a(b, b) = 7 +Let c = a(b + 6, b) +let c = c From 817549c78800bbe16fab8df3e62e9eac963964c3 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 17 Nov 2018 00:09:38 +0100 Subject: [PATCH 239/247] bugfix: read crash Parsing some READ sentences with semantic errors crashed the compiler. Fixed. --- tests/functional/read11.bas | 4 ++++ zxbparser.py | 3 +++ 2 files changed, 7 insertions(+) create mode 100644 tests/functional/read11.bas diff --git a/tests/functional/read11.bas b/tests/functional/read11.bas new file mode 100644 index 000000000..494aece19 --- /dev/null +++ b/tests/functional/read11.bas @@ -0,0 +1,4 @@ +1 BORDER 0: PAPER 0: INK 9: BRIGHT 1: CLS +10 LET spheres=2: IF spheres THEN DIM c(spheres,3): DIM r(spheres): DIM q(spheres) +20 FOR k=1 TO spheres: READ c(k,1),c(k,2),c(k,3),r: LET r(k)=r: LET q(k)=r*r: NEXT k + diff --git a/zxbparser.py b/zxbparser.py index 81f7a0e87..d603ea60d 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -1635,6 +1635,9 @@ def p_read(p): gl.DATA_IS_USED = True reads = [] + if p[2] is None: + return + for arg in p[2]: entry = arg.value if entry is None: From e6c9a55f877a5e8104492c37f8df23e17c9fc2f6 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 18 Nov 2018 22:35:00 +0100 Subject: [PATCH 240/247] Refact: use super instead of calling the base class constructor --- symbols/arrayaccess.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/symbols/arrayaccess.py b/symbols/arrayaccess.py index ba8d34920..d89ffec45 100644 --- a/symbols/arrayaccess.py +++ b/symbols/arrayaccess.py @@ -38,7 +38,7 @@ class SymbolARRAYACCESS(SymbolCALL): Arglist a SymbolARGLIST instance. """ def __init__(self, entry, arglist, lineno): - SymbolCALL.__init__(self, entry, arglist, lineno) + super(SymbolARRAYACCESS, self).__init__(entry, arglist, lineno) @property def entry(self): From acd6b4fa3ee09c600cb682555a5e358dcf8b7e8b Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 18 Nov 2018 22:35:18 +0100 Subject: [PATCH 241/247] Bugfix: READ should not recreate args When reading an array element, the args must be computed only once or array-base will be applied several times. --- tests/functional/arrbase1.asm | 1567 ++++++++++++++++++++++++++++++ tests/functional/arrbase1.bas | 10 + tests/functional/test_errmsg.txt | 1 + zxbparser.py | 4 +- 4 files changed, 1580 insertions(+), 2 deletions(-) create mode 100644 tests/functional/arrbase1.asm create mode 100644 tests/functional/arrbase1.bas diff --git a/tests/functional/arrbase1.asm b/tests/functional/arrbase1.asm new file mode 100644 index 000000000..9b392b2ef --- /dev/null +++ b/tests/functional/arrbase1.asm @@ -0,0 +1,1567 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld hl, 1 + ld (_k), hl + jp __LABEL0 +__LABEL3: + ld a, 2 + call __READ + push af + ld hl, 0 + push hl + ld hl, (_k) + dec hl + push hl + ld hl, _c + call __ARRAY + pop af + ld (hl), a +__LABEL4: + ld hl, (_k) + inc hl + ld (_k), hl +__LABEL0: + ld hl, 2 + ld de, (_k) + or a + sbc hl, de + jp nc, __LABEL3 +__LABEL2: + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__DATA__END: + DEFB 00h +#line 1 "array.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; ------------------------------------------------------------------- + ; Simple array Index routine + ; Number of total indexes dimensions - 1 at beginning of memory + ; HL = Start of array memory (First two bytes contains N-1 dimensions) + ; Dimension values on the stack, (top of the stack, highest dimension) + ; E.g. A(2, 4) -> PUSH <4>; PUSH <2> + + ; For any array of N dimension A(aN-1, ..., a1, a0) + ; and dimensions D[bN-1, ..., b1, b0], the offset is calculated as + ; O = [a0 + b0 * (a1 + b1 * (a2 + ... bN-2(aN-1)))] +; What I will do here is to calculate the following sequence: + ; ((aN-1 * bN-2) + aN-2) * bN-3 + ... + + +#line 1 "mul16.asm" + +__MUL16: ; Mutiplies HL with the last value stored into de stack + ; Works for both signed and unsigned + + PROC + + LOCAL __MUL16LOOP + LOCAL __MUL16NOADD + + ex de, hl + pop hl ; Return address + ex (sp), hl ; CALLEE caller convention + +;;__MUL16_FAST: ; __FASTCALL ENTRY: HL = 1st operand, DE = 2nd Operand + ;; ld c, h + ;; ld a, l ; C,A => 1st Operand + ;; + ;; ld hl, 0 ; Accumulator + ;; ld b, 16 + ;; +;;__MUL16LOOP: + ;; sra c ; C,A >> 1 (Arithmetic) + ;; rra + ;; + ;; jr nc, __MUL16NOADD + ;; add hl, de + ;; +;;__MUL16NOADD: + ;; sla e + ;; rl d + ;; + ;; djnz __MUL16LOOP + +__MUL16_FAST: + ld b, 16 + ld a, d + ld c, e + ex de, hl + ld hl, 0 + +__MUL16LOOP: + add hl, hl ; hl << 1 + sla c + rla ; a,c << 1 + jp nc, __MUL16NOADD + add hl, de + +__MUL16NOADD: + djnz __MUL16LOOP + + ret ; Result in hl (16 lower bits) + + ENDP + +#line 20 "array.asm" + +#line 24 "/src/zxb/trunk/library-asm/array.asm" + +__ARRAY: + PROC + + LOCAL LOOP + LOCAL ARRAY_END + LOCAL RET_ADDRESS ; Stores return address + + ex (sp), hl ; Return address in HL, array address in the stack + ld (RET_ADDRESS + 1), hl ; Stores it for later + + exx + pop hl ; Will use H'L' as the pointer + ld c, (hl) ; Loads Number of dimensions from (hl) + inc hl + ld b, (hl) + inc hl ; Ready + exx + + ld hl, 0 ; BC = Offset "accumulator" + +LOOP: +#line 49 "/src/zxb/trunk/library-asm/array.asm" + pop bc ; Get next index (Ai) from the stack + +#line 59 "/src/zxb/trunk/library-asm/array.asm" + + add hl, bc ; Adds current index + + exx ; Checks if B'C' = 0 + ld a, b ; Which means we must exit (last element is not multiplied by anything) + or c + jr z, ARRAY_END ; if B'Ci == 0 we are done + + ld e, (hl) ; Loads next dimension into D'E' + inc hl + ld d, (hl) + inc hl + push de + dec bc ; Decrements loop counter + exx + pop de ; DE = Max bound Number (i-th dimension) + + ;call __MUL16_FAST ; HL *= DE + call __FNMUL + jp LOOP + +ARRAY_END: + ld e, (hl) + inc hl + ld d, c ; C = 0 => DE = E = Element size + push hl + push de + exx + +#line 92 "/src/zxb/trunk/library-asm/array.asm" + LOCAL ARRAY_SIZE_LOOP + + ex de, hl + ld hl, 0 + pop bc + ld b, c +ARRAY_SIZE_LOOP: + add hl, de + djnz ARRAY_SIZE_LOOP + + ;; Even faster + ;pop bc + + ;ld d, h + ;ld e, l + + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, hl + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, hl + ;dec c + ;dec c + ;jp z, __ARRAY_FIN + + ;add hl, de + ;__ARRAY_FIN: +#line 123 "/src/zxb/trunk/library-asm/array.asm" + + pop de + add hl, de ; Adds element start + +RET_ADDRESS: + ld de, 0 + push de + ret ; HL = (Start of Elements + Offset) + + ;; Performs a faster multiply for little 16bit numbs + LOCAL __FNMUL, __FNMUL2 + +__FNMUL: + xor a + or d + jp nz, __MUL16_FAST + + or e + ex de, hl + ret z + + cp 33 + jp nc, __MUL16_FAST + + ld b, l + ld l, h ; HL = 0 + +__FNMUL2: + add hl, de + djnz __FNMUL2 + ret + + ENDP + +#line 47 "arrbase1.bas" +#line 1 "read_restore.asm" + + ;; This implements READ & RESTORE functions + ;; Reads a new element from the DATA Address code + ;; Updates the DATA_ADDR read ptr for the next read + + ;; Data codification is 1 byte for type followed by data bytes + ;; Byte type is encoded as follows + +;; 00: End of data +;; 01: String +;; 02: Byte +;; 03: Ubyte +;; 04: Integer +;; 05: UInteger +;; 06: Long +;; 07: ULong +;; 08: Fixed +;; 09: Float + + ;; bit7 is set for a parameter-less function + ;; In that case, the next two bytes are the ptr of the function to jump + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 23 "read_restore.asm" +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 70 "alloc.asm" + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 24 "read_restore.asm" +#line 1 "iload32.asm" + + ; __FASTCALL__ routine which + ; loads a 32 bits integer into DE,HL + ; stored at position pointed by POINTER HL + ; DE,HL <-- (HL) + +__ILOAD32: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + ex de, hl + ret + +#line 25 "read_restore.asm" +#line 1 "iloadf.asm" + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- ((HL)) + +__ILOADF: + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- (HL) + +__LOADF: ; Loads a 40 bits FP number from address pointed by HL + ld a, (hl) + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld c, (hl) + inc hl + ld b, (hl) + ret + +#line 26 "read_restore.asm" +#line 1 "ftof16reg.asm" + +#line 1 "ftou32reg.asm" + +#line 1 "neg32.asm" + +__ABS32: + bit 7, d + ret z + +__NEG32: ; Negates DEHL (Two's complement) + ld a, l + cpl + ld l, a + + ld a, h + cpl + ld h, a + + ld a, e + cpl + ld e, a + + ld a, d + cpl + ld d, a + + inc l + ret nz + + inc h + ret nz + + inc de + ret + +#line 2 "ftou32reg.asm" + +__FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + ; Output: DEHL 32 bit number (signed) + PROC + + LOCAL __IS_FLOAT + + or a + jr nz, __IS_FLOAT + ; Here if it is a ZX ROM Integer + + ld h, c + ld l, d + ld a, e ; Takes sign: FF = -, 0 = + + ld de, 0 + inc a + jp z, __NEG32 ; Negates if negative + ret + +__IS_FLOAT: ; Jumps here if it is a true floating point number + ld h, e + push hl ; Stores it for later (Contains Sign in H) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + ;ld a, c ; Get exponent + sub 128 ; Exponent -= 128 + jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + +__FTOU32REG_LOOP: + exx ; Shift C'B' E'D' << 1, output bit stays in Carry + sla d + rl e + rl b + rl c + + exx ; Shift DEHL << 1, inserting the carry on the right + rl l + rl h + rl e + rl d + + djnz __FTOU32REG_LOOP + +__FTOU32REG_END: + pop af ; Take the sign bit + or a ; Sets SGN bit to 1 if negative + jp m, __NEG32 ; Negates DEHL + + ret + + ENDP + + +__FTOU8: ; Converts float in C ED LH to Unsigned byte in A + call __FTOU32REG + ld a, l + ret + +#line 2 "ftof16reg.asm" + +__FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + + ld l, a ; Saves exponent for later + or d + or e + or b + or c + ld h, e + ret z ; Return if ZERO + + push hl ; Stores it for later (Contains sign in H, exponent in L) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + pop bc + + ld a, c ; Get exponent + sub 112 ; Exponent -= 128 + 16 + + push bc ; Saves sign in b again + + jp z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jp c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + 16 (we need to shift 16 bit more) + jp __FTOU32REG_LOOP ; proceed as an u32 integer + +#line 27 "read_restore.asm" +#line 1 "f16tofreg.asm" + + +#line 1 "u32tofreg.asm" + + +__I8TOFREG: + ld l, a + rlca + sbc a, a ; A = SGN(A) + ld h, a + ld e, a + ld d, a + +__I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) + ; to a Floating Point Number returned in (A ED CB) + + ld a, d + or a ; Test sign + + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __U32TOFREG ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + +__U8TOFREG: + ; Converts an unsigned 8 bit (A) to Floating point + ld l, a + ld h, 0 + ld e, h + ld d, h + +__U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in A ED CB + + PROC + + LOCAL __U32TOFREG_END + + ld a, d + or e + or h + or l + ld b, d + ld c, e ; Returns 00 0000 0000 if ZERO + ret z + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 128 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + +__U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG + exx + ld a, d ; B'C'D'E' == 0 ? + or e + or b + or c + jp z, __U32TOFREG_END ; We are done + + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry + rr c + rr d + rr e + exx + + rr e ; Shift EDCB >> 1, inserting the carry on the left + rr d + rr c + rr b + + inc l ; Increment exponent + jp __U32TOFREG_LOOP + + +__U32TOFREG_END: + exx + ld a, l ; Puts the exponent in a + res 7, e ; Sets the sign bit to 0 (positive) + + ret + ENDP + +#line 3 "f16tofreg.asm" + +__F16TOFREG: ; Converts a 16.16 signed fixed point (stored in DEHL) + ; to a Floating Point Number returned in (C ED CB) + PROC + + LOCAL __F16TOFREG2 + + ld a, d + or a ; Test sign + + jp p, __F16TOFREG2 ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __F16TOFREG2 ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + + +__F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in C DE HL + + ld a, d + or e + or h + or l + ld b, h + ld c, l + ret z ; Return 00 0000 0000 if 0 + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 112 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + jp __U32TOFREG_LOOP ; Proceed as an integer + + ENDP + +#line 28 "read_restore.asm" +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 29 "read_restore.asm" + + + + + + + + + + + + + ;; Updates restore point to the given HL mem. address +__RESTORE: + PROC + LOCAL __DATA_ADDR + + ld (__DATA_ADDR), hl + ret + + ;; Reads a value from the DATA mem area and updates __DATA_ADDR ptr to the + ;; next item. On Out Of Data, restarts + ;; +__READ: + LOCAL read_restart, cont, cont2, table, no_func + LOCAL dynamic_cast, dynamic_cast2, dynamic_cast3, dynamic_cast4 + LOCAL _decode_table, coerce_to_int, coerce_to_int2, promote_to_i16 + LOCAL _from_i8, _from_u8 + LOCAL _from_i16, _from_u16 + LOCAL _from_i32, _from_u32 + LOCAL _from_fixed, __data_error + + push af ; type of data to read + ld hl, (__DATA_ADDR) +read_restart: + ld a, (hl) + or a ; 0 => OUT of data + jr nz, cont + ;; Signals out of data + + ld hl, __DATA__0 + ld (__DATA_ADDR), hl + jr read_restart ; Start again +cont: + and 0x80 + ld a, (hl) + push af + jp z, no_func ;; Loads data directly, not a function + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl +cont2: + ld de, dynamic_cast + push de ; ret address + jp (hl) ; "call (hl)" + + ;; Now tries to convert the given result to the expected type or raise an error +dynamic_cast: + exx + ex af, af' + pop af ; type READ + and 0x7F ; clear bit 7 + pop hl ; type requested by USER (type of the READ variable) + ld c, h ; save requested type (save it in register C) + cp h + exx + jr nz, dynamic_cast2 ; Types are identical? + ;; yes, they are + ex af, af' + ret + +dynamic_cast2: + cp 1 ; Requested a number, but read a string? + jr nz, dynamic_cast3 + call __MEM_FREE ; Frees str from memory + jr __data_error + +dynamic_cast3: + exx + ld b, a ; Read type + ld a, c ; Requested type + cp 1 + jr z, __data_error + cp b + jr c, dynamic_cast4 + ;; here the user expected type is "larger" than the read one + ld a, b + sub 2 + add a, a + ld l, a + ld h, 0 + ld de, _decode_table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl + ld a, c ; Requested type + exx + ret + +__data_error: + ;; When a data is read, but cannot be converted to the requested type + ;; that is, the user asked for a string and we read a number or vice versa + ld a, ERROR_InvalidArg + call __STOP ; The user expected a string, but read a number + xor a + ld h, a + ld l, a + ld e, a + ld d, a + ld b, a + ld c, a + ret + +_decode_table: + dw _from_i8 + dw _from_u8 + dw _from_i16 + dw _from_u16 + dw _from_i32 + dw _from_u32 + dw _from_fixed + +_from_i8: + cp 4 + jr nc, promote_to_i16 + ex af, af' + ret ;; Was from Byte to Ubyte + +promote_to_i16: + ex af, af' + ld l, a + rla + sbc a, a + ld h, a ; copy sgn to h + ex af, af' + jr _before_from_i16 + +_from_u8: + ex af, af' + ld l, a + ld h, 0 + ex af, af' + ;; Promoted to i16 + +_before_from_i16: +_from_i16: + cp 6 + ret c ;; from i16 to u16 + ;; Promote i16 to i32 + ex af, af' + ld a, h + rla + sbc a, a + ld e, a + ld d, a + ex af, af' +_from_i32: + cp 7 + ret z ;; From i32 to u32 + ret c ;; From u16 to i32 + cp 9 + jp z, __I32TOFREG +_from_u32: + cp 9 + jp z, __U32TOFREG + ex de, hl + ld hl, 0 + cp 8 + ret z +_from_fixed: ;; From fixed to float + jp __F16TOFREG +_from_u16: + ld de, 0 ; HL 0x0000 => 32 bits + jp _from_i32 + +dynamic_cast4: + ;; The user type is "shorter" than the read one + cp 8 ;; required type + jr c, before_to_int ;; required < fixed (f16) + ex af, af' + exx ;; Ok, we must convert from float to f16 + jp __FTOF16REG + +before_to_int: + ld a, b ;; read type + cp 8 ;; + jr nz, coerce_to_int ;; From float to int + ld a, c ;; user type + exx + ;; f16 to Long + ex de, hl + ld a, h + rla + sbc a, a + ld d, a + ld e, a + exx + jr coerce_to_int2 +coerce_to_int: + exx + ex af, af' + call __FTOU32REG + ex af, af' ; a contains user type + exx +coerce_to_int2: ; At this point we have an u/integer in hl + exx + cp 4 + ret nc ; Already done. Return the result + ld a, l ; Truncate to byte + ret + +no_func: + exx + ld de, dynamic_cast + push de ; Ret address + dec a ; 0 => string; 1, 2 => byte; 3, 4 => integer; 5, 6 => long, 7 => fixed; 8 => float + ld h, 0 + add a, a + ld l, a + ld de, table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl ; address to jump to + exx + inc hl + ret ; jp (sp) => jump to table[a - 1] + +table: + LOCAL __01_decode_string + LOCAL __02_decode_byte + LOCAL __03_decode_ubyte + LOCAL __04_decode_integer + LOCAL __05_decode_uinteger + LOCAL __06_decode_long + LOCAL __07_decode_ulong + LOCAL __08_decode_fixed + LOCAL __09_decode_float + + ;; 1 -> Decode string + ;; 2, 3 -> Decode Byte, UByte + ;; 4, 5 -> Decode Integer, UInteger + ;; 6, 7 -> Decode Long, ULong + ;; 8 -> Decode Fixed + ;; 9 -> Decode Float + dw __01_decode_string + dw __02_decode_byte + dw __03_decode_ubyte + dw __04_decode_integer + dw __05_decode_uinteger + dw __06_decode_long + dw __07_decode_ulong + dw __08_decode_fixed + dw __09_decode_float + +__01_decode_string: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl + jp __LOADSTR + +__02_decode_byte: +__03_decode_ubyte: + ld a, (hl) + inc hl + ld (__DATA_ADDR), hl + ret + +__04_decode_integer: +__05_decode_uinteger: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl + ex de, hl + ret + +__06_decode_long: +__07_decode_ulong: +__08_decode_fixed: + ld b, h + ld c, l + inc bc + inc bc + inc bc + inc bc + ld (__DATA_ADDR), bc + jp __ILOAD32 + +__09_decode_float: + call __LOADF + inc hl + ld (__DATA_ADDR), hl + ld h, a ; returns A in H; sets A free + ret + +__DATA_ADDR: ;; Stores current DATA ptr + dw __DATA__0 + ENDP + + + + + + + + + + +#line 48 "arrbase1.bas" + +ZXBASIC_USER_DATA: +_k: + DEFB 00, 00 +_c: + DEFW 0001h + DEFW 0003h + DEFB 01h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h + DEFB 00h +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/arrbase1.bas b/tests/functional/arrbase1.bas new file mode 100644 index 000000000..0d60216f6 --- /dev/null +++ b/tests/functional/arrbase1.bas @@ -0,0 +1,10 @@ +' Test with Array Base = 1 +#pragma array_base = 1 + +DIM c(2, 3) as Byte +DIM k as Uinteger + +FOR k=1 TO 2 + READ c(k, 1) +NEXT k + diff --git a/tests/functional/test_errmsg.txt b/tests/functional/test_errmsg.txt index f643f8f78..73fa01dfe 100644 --- a/tests/functional/test_errmsg.txt +++ b/tests/functional/test_errmsg.txt @@ -138,4 +138,5 @@ params_implicit.bas:2: warning: Using default implicit type 'float' for 'y' params_implicit.bas:2: warning: Parameter 'y' is never used >>> process_file('array_err.bas') array_err.bas:2: Mismatched vector size. Expected 11 elements, got 1. +>>> process_file('arrbase1.bas') diff --git a/zxbparser.py b/zxbparser.py index d603ea60d..4b3ea2439 100755 --- a/zxbparser.py +++ b/zxbparser.py @@ -1663,8 +1663,8 @@ def p_read(p): reads.append(make_sentence('READ', entry)) continue - if isinstance(entry, symbols.ARRAYACCESS): - reads.append(make_sentence('READ', make_array_access(entry.entry.name, entry.lineno, entry.args))) + if isinstance(entry, symbols.ARRAYLOAD): + reads.append(make_sentence('READ', symbols.ARRAYACCESS(entry.entry, entry.args, entry.lineno))) continue api.errmsg.syntax_error(p.lineno(1), "Syntax error. Can only read a variable or an array element") From 500a49baf7c48acd35f06e6d2dc9e61071f35e7a Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 19 Nov 2018 01:27:59 +0100 Subject: [PATCH 242/247] Typo fix --- arch/zx48k/backend/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/zx48k/backend/__init__.py b/arch/zx48k/backend/__init__.py index e3330818d..136d3e0f0 100644 --- a/arch/zx48k/backend/__init__.py +++ b/arch/zx48k/backend/__init__.py @@ -446,7 +446,7 @@ def _deflabel(ins): def _data(ins): - """ Defines a data item (bynary). + """ Defines a data item (binary). It's just a constant expression to be converted do binary data "as is" 1st parameter is the type-size (u8 or i8 for byte, u16 or i16 for word, etc) From 2197142c7c8e6b9efd02feae91437d1a515525f8 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Mon, 19 Nov 2018 01:34:52 +0100 Subject: [PATCH 243/247] Bugfix: missing label err when no DATA is used When no DATA sentence is used, but READ is, a missing label error shows because a default one is not output to signal the beginning of the DATA zone. --- arch/zx48k/translator.py | 3 + tests/functional/arrbase1.asm | 5 +- tests/functional/readbug.asm | 1334 +++++++++++++++++++++++++++++++++ tests/functional/readbug.bas | 2 + 4 files changed, 1342 insertions(+), 2 deletions(-) create mode 100644 tests/functional/readbug.asm create mode 100644 tests/functional/readbug.bas diff --git a/arch/zx48k/translator.py b/arch/zx48k/translator.py index 90467f4bc..ea0fccbcd 100644 --- a/arch/zx48k/translator.py +++ b/arch/zx48k/translator.py @@ -190,6 +190,9 @@ def emit_data_blocks(self): else: self.emit('data', self.TSUFFIX(d.value.type_), [self.traverse_const(d.value)]) + if not gl.DATAS: # The above loop was not executed, because there's no data + self.emit('label', '__DATA__0') + self.emit('vard', '__DATA__END', ['00']) def emit_strings(self): diff --git a/tests/functional/arrbase1.asm b/tests/functional/arrbase1.asm index 9b392b2ef..df7e8a2de 100644 --- a/tests/functional/arrbase1.asm +++ b/tests/functional/arrbase1.asm @@ -56,6 +56,7 @@ __END_PROGRAM: ret __CALL_BACK__: DEFW 0 +__DATA__0: __DATA__END: DEFB 00h #line 1 "array.asm" @@ -257,7 +258,7 @@ __FNMUL2: ENDP -#line 47 "arrbase1.bas" +#line 48 "arrbase1.bas" #line 1 "read_restore.asm" ;; This implements READ & RESTORE functions @@ -1544,7 +1545,7 @@ __DATA_ADDR: ;; Stores current DATA ptr -#line 48 "arrbase1.bas" +#line 49 "arrbase1.bas" ZXBASIC_USER_DATA: _k: diff --git a/tests/functional/readbug.asm b/tests/functional/readbug.asm new file mode 100644 index 000000000..8e445fe5d --- /dev/null +++ b/tests/functional/readbug.asm @@ -0,0 +1,1334 @@ + org 32768 + ; Defines HEAP SIZE +ZXBASIC_HEAP_SIZE EQU 4768 +__START_PROGRAM: + di + push ix + push iy + exx + push hl + exx + ld hl, 0 + add hl, sp + ld (__CALL_BACK__), hl + ei + call __MEM_INIT + ld a, 3 + call __READ + ld (_r1), a + ld hl, 0 + ld b, h + ld c, l +__END_PROGRAM: + di + ld hl, (__CALL_BACK__) + ld sp, hl + exx + pop hl + exx + pop iy + pop ix + ei + ret +__CALL_BACK__: + DEFW 0 +__DATA__0: +__DATA__END: + DEFB 00h +#line 1 "read_restore.asm" + + ;; This implements READ & RESTORE functions + ;; Reads a new element from the DATA Address code + ;; Updates the DATA_ADDR read ptr for the next read + + ;; Data codification is 1 byte for type followed by data bytes + ;; Byte type is encoded as follows + +;; 00: End of data +;; 01: String +;; 02: Byte +;; 03: Ubyte +;; 04: Integer +;; 05: UInteger +;; 06: Long +;; 07: ULong +;; 08: Fixed +;; 09: Float + + ;; bit7 is set for a parameter-less function + ;; In that case, the next two bytes are the ptr of the function to jump + +#line 1 "error.asm" + + ; Simple error control routines +; vim:ts=4:et: + + ERR_NR EQU 23610 ; Error code system variable + + + ; Error code definitions (as in ZX spectrum manual) + +; Set error code with: + ; ld a, ERROR_CODE + ; ld (ERR_NR), a + + + ERROR_Ok EQU -1 + ERROR_SubscriptWrong EQU 2 + ERROR_OutOfMemory EQU 3 + ERROR_OutOfScreen EQU 4 + ERROR_NumberTooBig EQU 5 + ERROR_InvalidArg EQU 9 + ERROR_IntOutOfRange EQU 10 + ERROR_NonsenseInBasic EQU 11 + ERROR_InvalidFileName EQU 14 + ERROR_InvalidColour EQU 19 + ERROR_BreakIntoProgram EQU 20 + ERROR_TapeLoadingErr EQU 26 + + + ; Raises error using RST #8 +__ERROR: + ld (__ERROR_CODE), a + rst 8 +__ERROR_CODE: + nop + ret + + ; Sets the error system variable, but keeps running. + ; Usually this instruction if followed by the END intermediate instruction. +__STOP: + ld (ERR_NR), a + ret +#line 23 "read_restore.asm" +#line 1 "loadstr.asm" + +#line 1 "alloc.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be freed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + +#line 1 "heapinit.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- +__MEM_INIT: ; Initializes the library using (RAMTOP) as start, and + ld hl, ZXBASIC_MEM_HEAP ; Change this with other address of heap start + ld de, ZXBASIC_HEAP_SIZE ; Change this with your size + + ; --------------------------------------------------------------------- + ; __MEM_INIT2 initalizes this library +; Parameters: +; HL : Memory address of 1st byte of the memory heap +; DE : Length in bytes of the Memory Heap + ; --------------------------------------------------------------------- +__MEM_INIT2: + ; HL as TOP + PROC + + dec de + dec de + dec de + dec de ; DE = length - 4; HL = start + ; This is done, because we require 4 bytes for the empty dummy-header block + + xor a + ld (hl), a + inc hl + ld (hl), a ; First "free" block is a header: size=0, Pointer=&(Block) + 4 + inc hl + + ld b, h + ld c, l + inc bc + inc bc ; BC = starts of next block + + ld (hl), c + inc hl + ld (hl), b + inc hl ; Pointer to next block + + ld (hl), e + inc hl + ld (hl), d + inc hl ; Block size (should be length - 4 at start); This block contains all the available memory + + ld (hl), a ; NULL (0000h) ; No more blocks (a list with a single block) + inc hl + ld (hl), a + + ld a, 201 + ld (__MEM_INIT), a; "Pokes" with a RET so ensure this routine is not called again + ret + + ENDP + +#line 70 "alloc.asm" + + + ; --------------------------------------------------------------------- + ; MEM_ALLOC + ; Allocates a block of memory in the heap. + ; + ; Parameters + ; BC = Length of requested memory block + ; +; Returns: + ; HL = Pointer to the allocated block in memory. Returns 0 (NULL) + ; if the block could not be allocated (out of memory) + ; --------------------------------------------------------------------- + +MEM_ALLOC: +__MEM_ALLOC: ; Returns the 1st free block found of the given length (in BC) + PROC + + LOCAL __MEM_LOOP + LOCAL __MEM_DONE + LOCAL __MEM_SUBTRACT + LOCAL __MEM_START + LOCAL TEMP, TEMP0 + + TEMP EQU TEMP0 + 1 + + ld hl, 0 + ld (TEMP), hl + +__MEM_START: + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + inc bc + inc bc ; BC = BC + 2 ; block size needs 2 extra bytes for hidden pointer + +__MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE + ld a, h ; HL = NULL (No memory available?) + or l +#line 111 "/src/zxb/trunk/library-asm/alloc.asm" + ret z ; NULL +#line 113 "/src/zxb/trunk/library-asm/alloc.asm" + ; HL = Pointer to Free block + ld e, (hl) + inc hl + ld d, (hl) + inc hl ; DE = Block Length + + push hl ; HL = *pointer to -> next block + ex de, hl + or a ; CF = 0 + sbc hl, bc ; FREE >= BC (Length) (HL = BlockLength - Length) + jp nc, __MEM_DONE + pop hl + ld (TEMP), hl + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) + ex de, hl + jp __MEM_LOOP + +__MEM_DONE: ; A free block has been found. + ; Check if at least 4 bytes remains free (HL >= 4) + push hl + exx ; exx to preserve bc + pop hl + ld bc, 4 + or a + sbc hl, bc + exx + jp nc, __MEM_SUBTRACT + ; At this point... + ; less than 4 bytes remains free. So we return this block entirely + ; We must link the previous block with the next to this one + ; (DE) => Pointer to next block + ; (TEMP) => &(previous->next) + pop hl ; Discard current block pointer + push de + ex de, hl ; DE = Previous block pointer; (HL) = Next block pointer + ld a, (hl) + inc hl + ld h, (hl) + ld l, a ; HL = (HL) + ex de, hl ; HL = Previous block pointer; DE = Next block pointer +TEMP0: + ld hl, 0 ; Pre-previous block pointer + + ld (hl), e + inc hl + ld (hl), d ; LINKED + pop hl ; Returning block. + + ret + +__MEM_SUBTRACT: + ; At this point we have to store HL value (Length - BC) into (DE - 2) + ex de, hl + dec hl + ld (hl), d + dec hl + ld (hl), e ; Store new block length + + add hl, de ; New length + DE => free-block start + pop de ; Remove previous HL off the stack + + ld (hl), c ; Store length on its 1st word + inc hl + ld (hl), b + inc hl ; Return hl + ret + + ENDP + + +#line 2 "loadstr.asm" + + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + +__ILOADSTR: ; This is the indirect pointer entry HL = (HL) + ld a, h + or l + ret z + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + +__LOADSTR: ; __FASTCALL__ entry + ld a, h + or l + ret z ; Return if NULL + + ld c, (hl) + inc hl + ld b, (hl) + dec hl ; BC = LEN(a$) + + inc bc + inc bc ; BC = LEN(a$) + 2 (two bytes for length) + + push hl + push bc + call __MEM_ALLOC + pop bc ; Recover length + pop de ; Recover origin + + ld a, h + or l + ret z ; Return if NULL (No memory) + + ex de, hl ; ldir takes HL as source, DE as destiny, so SWAP HL,DE + push de ; Saves destiny start + ldir ; Copies string (length number included) + pop hl ; Recovers destiny in hl as result + ret +#line 24 "read_restore.asm" +#line 1 "iload32.asm" + + ; __FASTCALL__ routine which + ; loads a 32 bits integer into DE,HL + ; stored at position pointed by POINTER HL + ; DE,HL <-- (HL) + +__ILOAD32: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + ex de, hl + ret + +#line 25 "read_restore.asm" +#line 1 "iloadf.asm" + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- ((HL)) + +__ILOADF: + ld a, (hl) + inc hl + ld h, (hl) + ld l, a + + ; __FASTCALL__ routine which + ; loads a 40 bits floating point into A ED CB + ; stored at position pointed by POINTER HL + ;A DE, BC <-- (HL) + +__LOADF: ; Loads a 40 bits FP number from address pointed by HL + ld a, (hl) + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld c, (hl) + inc hl + ld b, (hl) + ret + +#line 26 "read_restore.asm" +#line 1 "ftof16reg.asm" + +#line 1 "ftou32reg.asm" + +#line 1 "neg32.asm" + +__ABS32: + bit 7, d + ret z + +__NEG32: ; Negates DEHL (Two's complement) + ld a, l + cpl + ld l, a + + ld a, h + cpl + ld h, a + + ld a, e + cpl + ld e, a + + ld a, d + cpl + ld d, a + + inc l + ret nz + + inc h + ret nz + + inc de + ret + +#line 2 "ftou32reg.asm" + +__FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS 32 bit signed) + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + ; Output: DEHL 32 bit number (signed) + PROC + + LOCAL __IS_FLOAT + + or a + jr nz, __IS_FLOAT + ; Here if it is a ZX ROM Integer + + ld h, c + ld l, d + ld a, e ; Takes sign: FF = -, 0 = + + ld de, 0 + inc a + jp z, __NEG32 ; Negates if negative + ret + +__IS_FLOAT: ; Jumps here if it is a true floating point number + ld h, e + push hl ; Stores it for later (Contains Sign in H) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + ;ld a, c ; Get exponent + sub 128 ; Exponent -= 128 + jr z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jr c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + +__FTOU32REG_LOOP: + exx ; Shift C'B' E'D' << 1, output bit stays in Carry + sla d + rl e + rl b + rl c + + exx ; Shift DEHL << 1, inserting the carry on the right + rl l + rl h + rl e + rl d + + djnz __FTOU32REG_LOOP + +__FTOU32REG_END: + pop af ; Take the sign bit + or a ; Sets SGN bit to 1 if negative + jp m, __NEG32 ; Negates DEHL + + ret + + ENDP + + +__FTOU8: ; Converts float in C ED LH to Unsigned byte in A + call __FTOU32REG + ld a, l + ret + +#line 2 "ftof16reg.asm" + +__FTOF16REG: ; Converts a Float to 16.16 (32 bit) fixed point decimal + ; Input FP number in A EDCB (A exponent, EDCB mantissa) + + ld l, a ; Saves exponent for later + or d + or e + or b + or c + ld h, e + ret z ; Return if ZERO + + push hl ; Stores it for later (Contains sign in H, exponent in L) + + push de + push bc + + exx + pop de ; Loads mantissa into C'B' E'D' + pop bc ; + + set 7, c ; Highest mantissa bit is always 1 + exx + + ld hl, 0 ; DEHL = 0 + ld d, h + ld e, l + + pop bc + + ld a, c ; Get exponent + sub 112 ; Exponent -= 128 + 16 + + push bc ; Saves sign in b again + + jp z, __FTOU32REG_END ; If it was <= 128, we are done (Integers must be > 128) + jp c, __FTOU32REG_END ; It was decimal (0.xxx). We are done (return 0) + + ld b, a ; Loop counter = exponent - 128 + 16 (we need to shift 16 bit more) + jp __FTOU32REG_LOOP ; proceed as an u32 integer + +#line 27 "read_restore.asm" +#line 1 "f16tofreg.asm" + + +#line 1 "u32tofreg.asm" + + +__I8TOFREG: + ld l, a + rlca + sbc a, a ; A = SGN(A) + ld h, a + ld e, a + ld d, a + +__I32TOFREG: ; Converts a 32bit signed integer (stored in DEHL) + ; to a Floating Point Number returned in (A ED CB) + + ld a, d + or a ; Test sign + + jp p, __U32TOFREG ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __U32TOFREG ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + +__U8TOFREG: + ; Converts an unsigned 8 bit (A) to Floating point + ld l, a + ld h, 0 + ld e, h + ld d, h + +__U32TOFREG: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in A ED CB + + PROC + + LOCAL __U32TOFREG_END + + ld a, d + or e + or h + or l + ld b, d + ld c, e ; Returns 00 0000 0000 if ZERO + ret z + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 128 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + +__U32TOFREG_LOOP: ; Also an entry point for __F16TOFREG + exx + ld a, d ; B'C'D'E' == 0 ? + or e + or b + or c + jp z, __U32TOFREG_END ; We are done + + srl b ; Shift B'C' D'E' >> 1, output bit stays in Carry + rr c + rr d + rr e + exx + + rr e ; Shift EDCB >> 1, inserting the carry on the left + rr d + rr c + rr b + + inc l ; Increment exponent + jp __U32TOFREG_LOOP + + +__U32TOFREG_END: + exx + ld a, l ; Puts the exponent in a + res 7, e ; Sets the sign bit to 0 (positive) + + ret + ENDP + +#line 3 "f16tofreg.asm" + +__F16TOFREG: ; Converts a 16.16 signed fixed point (stored in DEHL) + ; to a Floating Point Number returned in (C ED CB) + PROC + + LOCAL __F16TOFREG2 + + ld a, d + or a ; Test sign + + jp p, __F16TOFREG2 ; It was positive, proceed as 32bit unsigned + + call __NEG32 ; Convert it to positive + call __F16TOFREG2 ; Convert it to Floating point + + set 7, e ; Put the sign bit (negative) in the 31bit of mantissa + ret + + +__F16TOFREG2: ; Converts an unsigned 32 bit integer (DEHL) + ; to a Floating point number returned in C DE HL + + ld a, d + or e + or h + or l + ld b, h + ld c, l + ret z ; Return 00 0000 0000 if 0 + + push de + push hl + + exx + pop de ; Loads integer into B'C' D'E' + pop bc + exx + + ld l, 112 ; Exponent + ld bc, 0 ; DEBC = 0 + ld d, b + ld e, c + jp __U32TOFREG_LOOP ; Proceed as an integer + + ENDP + +#line 28 "read_restore.asm" +#line 1 "free.asm" + +; vim: ts=4:et:sw=4: + ; Copyleft (K) by Jose M. Rodriguez de la Rosa + ; (a.k.a. Boriel) +; http://www.boriel.com + ; + ; This ASM library is licensed under the BSD license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the BSD license on the internet + + ; ----- IMPLEMENTATION NOTES ------ + ; The heap is implemented as a linked list of free blocks. + +; Each free block contains this info: + ; + ; +----------------+ <-- HEAP START + ; | Size (2 bytes) | + ; | 0 | <-- Size = 0 => DUMMY HEADER BLOCK + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | <-- If Size > 4, then this contains (size - 4) bytes + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ | + ; | <-- This zone is in use (Already allocated) + ; +----------------+ <-+ + ; | Size (2 bytes) | + ; +----------------+ + ; | Next (2 bytes) |---+ + ; +----------------+ | + ; | | | + ; | (0 if Size = 4)| | + ; +----------------+ <-+ + ; | Next (2 bytes) |--> NULL => END OF LIST + ; | 0 = NULL | + ; +----------------+ + ; | | + ; | (0 if Size = 4)| + ; +----------------+ + + + ; When a block is FREED, the previous and next pointers are examined to see + ; if we can defragment the heap. If the block to be breed is just next to the + ; previous, or to the next (or both) they will be converted into a single + ; block (so defragmented). + + + ; MEMORY MANAGER + ; + ; This library must be initialized calling __MEM_INIT with + ; HL = BLOCK Start & DE = Length. + + ; An init directive is useful for initialization routines. + ; They will be added automatically if needed. + + + + ; --------------------------------------------------------------------- + ; MEM_FREE + ; Frees a block of memory + ; +; Parameters: + ; HL = Pointer to the block to be freed. If HL is NULL (0) nothing + ; is done + ; --------------------------------------------------------------------- + +MEM_FREE: +__MEM_FREE: ; Frees the block pointed by HL + ; HL DE BC & AF modified + PROC + + LOCAL __MEM_LOOP2 + LOCAL __MEM_LINK_PREV + LOCAL __MEM_JOIN_TEST + LOCAL __MEM_BLOCK_JOIN + + ld a, h + or l + ret z ; Return if NULL pointer + + dec hl + dec hl + ld b, h + ld c, l ; BC = Block pointer + + ld hl, ZXBASIC_MEM_HEAP ; This label point to the heap start + +__MEM_LOOP2: + inc hl + inc hl ; Next block ptr + + ld e, (hl) + inc hl + ld d, (hl) ; Block next ptr + ex de, hl ; DE = &(block->next); HL = block->next + + ld a, h ; HL == NULL? + or l + jp z, __MEM_LINK_PREV; if so, link with previous + + or a ; Clear carry flag + sbc hl, bc ; Carry if BC > HL => This block if before + add hl, bc ; Restores HL, preserving Carry flag + jp c, __MEM_LOOP2 ; This block is before. Keep searching PASS the block + + ;------ At this point current HL is PAST BC, so we must link (DE) with BC, and HL in BC->next + +__MEM_LINK_PREV: ; Link (DE) with BC, and BC->next with HL + ex de, hl + push hl + dec hl + + ld (hl), c + inc hl + ld (hl), b ; (DE) <- BC + + ld h, b ; HL <- BC (Free block ptr) + ld l, c + inc hl ; Skip block length (2 bytes) + inc hl + ld (hl), e ; Block->next = DE + inc hl + ld (hl), d + ; --- LINKED ; HL = &(BC->next) + 2 + + call __MEM_JOIN_TEST + pop hl + +__MEM_JOIN_TEST: ; Checks for fragmented contiguous blocks and joins them + ; hl = Ptr to current block + 2 + ld d, (hl) + dec hl + ld e, (hl) + dec hl + ld b, (hl) ; Loads block length into BC + dec hl + ld c, (hl) ; + + push hl ; Saves it for later + add hl, bc ; Adds its length. If HL == DE now, it must be joined + or a + sbc hl, de ; If Z, then HL == DE => We must join + pop hl + ret nz + +__MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed by DE). HL->length already in BC + push hl ; Saves it for later + ex de, hl + + ld e, (hl) ; DE -> block->next->length + inc hl + ld d, (hl) + inc hl + + ex de, hl ; DE = &(block->next) + add hl, bc ; HL = Total Length + + ld b, h + ld c, l ; BC = Total Length + + ex de, hl + ld e, (hl) + inc hl + ld d, (hl) ; DE = block->next + + pop hl ; Recovers Pointer to block + ld (hl), c + inc hl + ld (hl), b ; Length Saved + inc hl + ld (hl), e + inc hl + ld (hl), d ; Next saved + ret + + ENDP + +#line 29 "read_restore.asm" + + + + + + + + + + + + + ;; Updates restore point to the given HL mem. address +__RESTORE: + PROC + LOCAL __DATA_ADDR + + ld (__DATA_ADDR), hl + ret + + ;; Reads a value from the DATA mem area and updates __DATA_ADDR ptr to the + ;; next item. On Out Of Data, restarts + ;; +__READ: + LOCAL read_restart, cont, cont2, table, no_func + LOCAL dynamic_cast, dynamic_cast2, dynamic_cast3, dynamic_cast4 + LOCAL _decode_table, coerce_to_int, coerce_to_int2, promote_to_i16 + LOCAL _from_i8, _from_u8 + LOCAL _from_i16, _from_u16 + LOCAL _from_i32, _from_u32 + LOCAL _from_fixed, __data_error + + push af ; type of data to read + ld hl, (__DATA_ADDR) +read_restart: + ld a, (hl) + or a ; 0 => OUT of data + jr nz, cont + ;; Signals out of data + + ld hl, __DATA__0 + ld (__DATA_ADDR), hl + jr read_restart ; Start again +cont: + and 0x80 + ld a, (hl) + push af + jp z, no_func ;; Loads data directly, not a function + inc hl + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl +cont2: + ld de, dynamic_cast + push de ; ret address + jp (hl) ; "call (hl)" + + ;; Now tries to convert the given result to the expected type or raise an error +dynamic_cast: + exx + ex af, af' + pop af ; type READ + and 0x7F ; clear bit 7 + pop hl ; type requested by USER (type of the READ variable) + ld c, h ; save requested type (save it in register C) + cp h + exx + jr nz, dynamic_cast2 ; Types are identical? + ;; yes, they are + ex af, af' + ret + +dynamic_cast2: + cp 1 ; Requested a number, but read a string? + jr nz, dynamic_cast3 + call __MEM_FREE ; Frees str from memory + jr __data_error + +dynamic_cast3: + exx + ld b, a ; Read type + ld a, c ; Requested type + cp 1 + jr z, __data_error + cp b + jr c, dynamic_cast4 + ;; here the user expected type is "larger" than the read one + ld a, b + sub 2 + add a, a + ld l, a + ld h, 0 + ld de, _decode_table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl + ld a, c ; Requested type + exx + ret + +__data_error: + ;; When a data is read, but cannot be converted to the requested type + ;; that is, the user asked for a string and we read a number or vice versa + ld a, ERROR_InvalidArg + call __STOP ; The user expected a string, but read a number + xor a + ld h, a + ld l, a + ld e, a + ld d, a + ld b, a + ld c, a + ret + +_decode_table: + dw _from_i8 + dw _from_u8 + dw _from_i16 + dw _from_u16 + dw _from_i32 + dw _from_u32 + dw _from_fixed + +_from_i8: + cp 4 + jr nc, promote_to_i16 + ex af, af' + ret ;; Was from Byte to Ubyte + +promote_to_i16: + ex af, af' + ld l, a + rla + sbc a, a + ld h, a ; copy sgn to h + ex af, af' + jr _before_from_i16 + +_from_u8: + ex af, af' + ld l, a + ld h, 0 + ex af, af' + ;; Promoted to i16 + +_before_from_i16: +_from_i16: + cp 6 + ret c ;; from i16 to u16 + ;; Promote i16 to i32 + ex af, af' + ld a, h + rla + sbc a, a + ld e, a + ld d, a + ex af, af' +_from_i32: + cp 7 + ret z ;; From i32 to u32 + ret c ;; From u16 to i32 + cp 9 + jp z, __I32TOFREG +_from_u32: + cp 9 + jp z, __U32TOFREG + ex de, hl + ld hl, 0 + cp 8 + ret z +_from_fixed: ;; From fixed to float + jp __F16TOFREG +_from_u16: + ld de, 0 ; HL 0x0000 => 32 bits + jp _from_i32 + +dynamic_cast4: + ;; The user type is "shorter" than the read one + cp 8 ;; required type + jr c, before_to_int ;; required < fixed (f16) + ex af, af' + exx ;; Ok, we must convert from float to f16 + jp __FTOF16REG + +before_to_int: + ld a, b ;; read type + cp 8 ;; + jr nz, coerce_to_int ;; From float to int + ld a, c ;; user type + exx + ;; f16 to Long + ex de, hl + ld a, h + rla + sbc a, a + ld d, a + ld e, a + exx + jr coerce_to_int2 +coerce_to_int: + exx + ex af, af' + call __FTOU32REG + ex af, af' ; a contains user type + exx +coerce_to_int2: ; At this point we have an u/integer in hl + exx + cp 4 + ret nc ; Already done. Return the result + ld a, l ; Truncate to byte + ret + +no_func: + exx + ld de, dynamic_cast + push de ; Ret address + dec a ; 0 => string; 1, 2 => byte; 3, 4 => integer; 5, 6 => long, 7 => fixed; 8 => float + ld h, 0 + add a, a + ld l, a + ld de, table + add hl, de + ld e, (hl) + inc hl + ld h, (hl) + ld l, e + push hl ; address to jump to + exx + inc hl + ret ; jp (sp) => jump to table[a - 1] + +table: + LOCAL __01_decode_string + LOCAL __02_decode_byte + LOCAL __03_decode_ubyte + LOCAL __04_decode_integer + LOCAL __05_decode_uinteger + LOCAL __06_decode_long + LOCAL __07_decode_ulong + LOCAL __08_decode_fixed + LOCAL __09_decode_float + + ;; 1 -> Decode string + ;; 2, 3 -> Decode Byte, UByte + ;; 4, 5 -> Decode Integer, UInteger + ;; 6, 7 -> Decode Long, ULong + ;; 8 -> Decode Fixed + ;; 9 -> Decode Float + dw __01_decode_string + dw __02_decode_byte + dw __03_decode_ubyte + dw __04_decode_integer + dw __05_decode_uinteger + dw __06_decode_long + dw __07_decode_ulong + dw __08_decode_fixed + dw __09_decode_float + +__01_decode_string: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl ;; Store address of next DATA + ex de, hl + jp __LOADSTR + +__02_decode_byte: +__03_decode_ubyte: + ld a, (hl) + inc hl + ld (__DATA_ADDR), hl + ret + +__04_decode_integer: +__05_decode_uinteger: + ld e, (hl) + inc hl + ld d, (hl) + inc hl + ld (__DATA_ADDR), hl + ex de, hl + ret + +__06_decode_long: +__07_decode_ulong: +__08_decode_fixed: + ld b, h + ld c, l + inc bc + inc bc + inc bc + inc bc + ld (__DATA_ADDR), bc + jp __ILOAD32 + +__09_decode_float: + call __LOADF + inc hl + ld (__DATA_ADDR), hl + ld h, a ; returns A in H; sets A free + ret + +__DATA_ADDR: ;; Stores current DATA ptr + dw __DATA__0 + ENDP + + + + + + + + + + +#line 24 "readbug.bas" + +ZXBASIC_USER_DATA: +_r1: + DEFB 00 +ZXBASIC_MEM_HEAP: + ; Defines DATA END +ZXBASIC_USER_DATA_END EQU ZXBASIC_MEM_HEAP + ZXBASIC_HEAP_SIZE + ; Defines USER DATA Length in bytes +ZXBASIC_USER_DATA_LEN EQU ZXBASIC_USER_DATA_END - ZXBASIC_USER_DATA + END diff --git a/tests/functional/readbug.bas b/tests/functional/readbug.bas new file mode 100644 index 000000000..ca257f122 --- /dev/null +++ b/tests/functional/readbug.bas @@ -0,0 +1,2 @@ +DIM r1 as UByte +READ r1 From 6afb40628a6a2877a70ff6dd93f76d3a843f264d Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 21 Oct 2018 22:55:02 +0200 Subject: [PATCH 244/247] make int to behave as BASIC INT This way INT is more compatible and behaves like INT function in Sinclair BASIC --- library-asm/ftou32reg.asm | 19 +++++++++++++- tests/functional/70.asm | 19 +++++++++++++- tests/functional/arrbase1.asm | 33 +++++++++++++++++++------ tests/functional/circle.asm | 19 +++++++++++++- tests/functional/coercion1.asm | 19 +++++++++++++- tests/functional/div32.asm | 19 +++++++++++++- tests/functional/dountilsplitted.asm | 19 +++++++++++++- tests/functional/dowhilesplitted.asm | 19 +++++++++++++- tests/functional/draw.asm | 19 +++++++++++++- tests/functional/draw3.asm | 19 +++++++++++++- tests/functional/eq0.asm | 19 +++++++++++++- tests/functional/funcif.asm | 19 +++++++++++++- tests/functional/ifcrash.asm | 19 +++++++++++++- tests/functional/lcd3.asm | 27 ++++++++++++++++---- tests/functional/mcleod.asm | 19 +++++++++++++- tests/functional/opt3_data2.asm | 37 ++++++++++++++++++++-------- tests/functional/opt3_lcd5.asm | 19 +++++++++++++- tests/functional/optspeed.asm | 19 +++++++++++++- tests/functional/out0.asm | 19 +++++++++++++- tests/functional/plot.asm | 19 +++++++++++++- tests/functional/read.asm | 23 ++++++++++++++--- tests/functional/read10.asm | 27 ++++++++++++++++---- tests/functional/read12.asm | 27 ++++++++++++++++---- tests/functional/read4.asm | 23 ++++++++++++++--- tests/functional/read5.asm | 27 ++++++++++++++++---- tests/functional/read8.asm | 27 ++++++++++++++++---- tests/functional/read9.asm | 37 ++++++++++++++++++++-------- tests/functional/readbug.asm | 23 ++++++++++++++--- tests/functional/readokdown.asm | 27 ++++++++++++++++---- tests/functional/readokup.asm | 27 ++++++++++++++++---- tests/functional/strsigil.asm | 23 ++++++++++++++--- tests/functional/test.py | 5 ++-- tests/functional/while.asm | 19 +++++++++++++- tests/functional/whilesplitted.asm | 19 +++++++++++++- 34 files changed, 657 insertions(+), 97 deletions(-) diff --git a/library-asm/ftou32reg.asm b/library-asm/ftou32reg.asm index 394bda4fb..d2e3e9e04 100644 --- a/library-asm/ftou32reg.asm +++ b/library-asm/ftou32reg.asm @@ -6,6 +6,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -62,10 +63,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de +LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/70.asm b/tests/functional/70.asm index c85ea7731..d37ea9d70 100644 --- a/tests/functional/70.asm +++ b/tests/functional/70.asm @@ -161,6 +161,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -217,10 +218,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/arrbase1.asm b/tests/functional/arrbase1.asm index df7e8a2de..61d89fd7c 100644 --- a/tests/functional/arrbase1.asm +++ b/tests/functional/arrbase1.asm @@ -136,7 +136,7 @@ __MUL16NOADD: #line 20 "array.asm" -#line 24 "/src/zxb/trunk/library-asm/array.asm" +#line 24 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/array.asm" __ARRAY: PROC @@ -159,10 +159,10 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" LOOP: -#line 49 "/src/zxb/trunk/library-asm/array.asm" +#line 49 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 59 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/array.asm" add hl, bc ; Adds current index @@ -192,7 +192,7 @@ ARRAY_END: push de exx -#line 92 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -223,7 +223,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 123 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/array.asm" pop de add hl, de ; Adds element start @@ -562,9 +562,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/src/zxb/trunk/library-asm/alloc.asm" +#line 111 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ret z ; NULL -#line 113 "/src/zxb/trunk/library-asm/alloc.asm" +#line 113 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -778,6 +778,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -834,10 +835,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/circle.asm b/tests/functional/circle.asm index 6c709a2f9..163fb707a 100644 --- a/tests/functional/circle.asm +++ b/tests/functional/circle.asm @@ -588,6 +588,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -644,10 +645,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/coercion1.asm b/tests/functional/coercion1.asm index ba98b26ce..d063e4da8 100644 --- a/tests/functional/coercion1.asm +++ b/tests/functional/coercion1.asm @@ -295,6 +295,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -351,10 +352,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/div32.asm b/tests/functional/div32.asm index b98e9efa1..e5877898f 100644 --- a/tests/functional/div32.asm +++ b/tests/functional/div32.asm @@ -172,6 +172,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -228,10 +229,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/dountilsplitted.asm b/tests/functional/dountilsplitted.asm index 4459e4f7a..cc2091024 100644 --- a/tests/functional/dountilsplitted.asm +++ b/tests/functional/dountilsplitted.asm @@ -190,6 +190,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -246,10 +247,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/dowhilesplitted.asm b/tests/functional/dowhilesplitted.asm index 44726bab0..3735e3e46 100644 --- a/tests/functional/dowhilesplitted.asm +++ b/tests/functional/dowhilesplitted.asm @@ -190,6 +190,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -246,10 +247,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/draw.asm b/tests/functional/draw.asm index eb0e923eb..351e83dfb 100644 --- a/tests/functional/draw.asm +++ b/tests/functional/draw.asm @@ -750,6 +750,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -806,10 +807,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/draw3.asm b/tests/functional/draw3.asm index e142351cb..d7ad6f774 100644 --- a/tests/functional/draw3.asm +++ b/tests/functional/draw3.asm @@ -1424,6 +1424,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -1480,10 +1481,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/eq0.asm b/tests/functional/eq0.asm index 2356d1cc5..50601daab 100644 --- a/tests/functional/eq0.asm +++ b/tests/functional/eq0.asm @@ -169,6 +169,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -225,10 +226,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/funcif.asm b/tests/functional/funcif.asm index 0139d42a9..ea11b257d 100644 --- a/tests/functional/funcif.asm +++ b/tests/functional/funcif.asm @@ -114,6 +114,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -170,10 +171,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/ifcrash.asm b/tests/functional/ifcrash.asm index 8a467c559..89caaf8f5 100644 --- a/tests/functional/ifcrash.asm +++ b/tests/functional/ifcrash.asm @@ -233,6 +233,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -289,10 +290,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/lcd3.asm b/tests/functional/lcd3.asm index 5fbc33539..e22716e4b 100644 --- a/tests/functional/lcd3.asm +++ b/tests/functional/lcd3.asm @@ -585,6 +585,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -641,10 +642,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP @@ -806,9 +823,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/src/zxb/trunk/library-asm/alloc.asm" +#line 111 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ret z ; NULL -#line 113 "/src/zxb/trunk/library-asm/alloc.asm" +#line 113 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -1242,7 +1259,7 @@ BRIGHT_TMP: -#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" +#line 4 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" @@ -1301,7 +1318,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" +#line 65 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) diff --git a/tests/functional/mcleod.asm b/tests/functional/mcleod.asm index fc38a8078..8344c5eda 100644 --- a/tests/functional/mcleod.asm +++ b/tests/functional/mcleod.asm @@ -79,6 +79,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -135,10 +136,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/opt3_data2.asm b/tests/functional/opt3_data2.asm index 71b41a3e7..c11f8bb81 100644 --- a/tests/functional/opt3_data2.asm +++ b/tests/functional/opt3_data2.asm @@ -186,7 +186,7 @@ __MUL16NOADD: #line 20 "array.asm" -#line 24 "/src/zxb/trunk/library-asm/array.asm" +#line 24 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/array.asm" __ARRAY: PROC @@ -209,10 +209,10 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" LOOP: -#line 49 "/src/zxb/trunk/library-asm/array.asm" +#line 49 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 59 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/array.asm" add hl, bc ; Adds current index @@ -242,7 +242,7 @@ ARRAY_END: push de exx -#line 92 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -273,7 +273,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 123 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/array.asm" pop de add hl, de ; Adds element start @@ -720,7 +720,7 @@ BRIGHT_TMP: -#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" +#line 4 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" @@ -779,7 +779,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" +#line 65 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -1918,9 +1918,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/src/zxb/trunk/library-asm/alloc.asm" +#line 111 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ret z ; NULL -#line 113 "/src/zxb/trunk/library-asm/alloc.asm" +#line 113 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -2134,6 +2134,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -2190,10 +2191,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/opt3_lcd5.asm b/tests/functional/opt3_lcd5.asm index ea70741b8..ae6cdd401 100644 --- a/tests/functional/opt3_lcd5.asm +++ b/tests/functional/opt3_lcd5.asm @@ -413,6 +413,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -469,10 +470,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/optspeed.asm b/tests/functional/optspeed.asm index f79e8b17d..d22ab78d9 100644 --- a/tests/functional/optspeed.asm +++ b/tests/functional/optspeed.asm @@ -505,6 +505,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -561,10 +562,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/out0.asm b/tests/functional/out0.asm index b06c66cc1..2a84fc853 100644 --- a/tests/functional/out0.asm +++ b/tests/functional/out0.asm @@ -78,6 +78,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -134,10 +135,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/plot.asm b/tests/functional/plot.asm index af14b406c..7c5835b7f 100644 --- a/tests/functional/plot.asm +++ b/tests/functional/plot.asm @@ -100,6 +100,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -156,10 +157,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/read.asm b/tests/functional/read.asm index a13c5c1ff..cba30ec0c 100644 --- a/tests/functional/read.asm +++ b/tests/functional/read.asm @@ -340,9 +340,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/src/zxb/trunk/library-asm/alloc.asm" +#line 111 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ret z ; NULL -#line 113 "/src/zxb/trunk/library-asm/alloc.asm" +#line 113 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -581,6 +581,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -637,10 +638,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/read10.asm b/tests/functional/read10.asm index 7544b1a37..63b5422f5 100644 --- a/tests/functional/read10.asm +++ b/tests/functional/read10.asm @@ -639,7 +639,7 @@ BRIGHT_TMP: -#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" +#line 4 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" @@ -698,7 +698,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" +#line 65 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -2012,9 +2012,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/src/zxb/trunk/library-asm/alloc.asm" +#line 111 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ret z ; NULL -#line 113 "/src/zxb/trunk/library-asm/alloc.asm" +#line 113 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -2198,6 +2198,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -2254,10 +2255,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/read12.asm b/tests/functional/read12.asm index 1dd151522..fe10fb682 100644 --- a/tests/functional/read12.asm +++ b/tests/functional/read12.asm @@ -344,9 +344,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/src/zxb/trunk/library-asm/alloc.asm" +#line 111 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ret z ; NULL -#line 113 "/src/zxb/trunk/library-asm/alloc.asm" +#line 113 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -780,7 +780,7 @@ BRIGHT_TMP: -#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" +#line 4 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" @@ -839,7 +839,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" +#line 65 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -1833,6 +1833,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -1889,10 +1890,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/read4.asm b/tests/functional/read4.asm index c4c812b36..1b9ac7d58 100644 --- a/tests/functional/read4.asm +++ b/tests/functional/read4.asm @@ -383,9 +383,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/src/zxb/trunk/library-asm/alloc.asm" +#line 111 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ret z ; NULL -#line 113 "/src/zxb/trunk/library-asm/alloc.asm" +#line 113 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -760,6 +760,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -816,10 +817,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/read5.asm b/tests/functional/read5.asm index 0b0d9e6fe..9b0a02e7d 100644 --- a/tests/functional/read5.asm +++ b/tests/functional/read5.asm @@ -587,7 +587,7 @@ BRIGHT_TMP: -#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" +#line 4 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" @@ -646,7 +646,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" +#line 65 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -1910,9 +1910,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/src/zxb/trunk/library-asm/alloc.asm" +#line 111 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ret z ; NULL -#line 113 "/src/zxb/trunk/library-asm/alloc.asm" +#line 113 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -2126,6 +2126,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -2182,10 +2183,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/read8.asm b/tests/functional/read8.asm index cc7e85170..ed27a823d 100644 --- a/tests/functional/read8.asm +++ b/tests/functional/read8.asm @@ -578,7 +578,7 @@ BRIGHT_TMP: -#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" +#line 4 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" @@ -637,7 +637,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" +#line 65 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -1901,9 +1901,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/src/zxb/trunk/library-asm/alloc.asm" +#line 111 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ret z ; NULL -#line 113 "/src/zxb/trunk/library-asm/alloc.asm" +#line 113 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -2117,6 +2117,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -2173,10 +2174,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/read9.asm b/tests/functional/read9.asm index 043aa4b28..545e6a697 100644 --- a/tests/functional/read9.asm +++ b/tests/functional/read9.asm @@ -208,7 +208,7 @@ __MUL16NOADD: #line 20 "array.asm" -#line 24 "/src/zxb/trunk/library-asm/array.asm" +#line 24 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/array.asm" __ARRAY: PROC @@ -231,10 +231,10 @@ __ARRAY: ld hl, 0 ; BC = Offset "accumulator" LOOP: -#line 49 "/src/zxb/trunk/library-asm/array.asm" +#line 49 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/array.asm" pop bc ; Get next index (Ai) from the stack -#line 59 "/src/zxb/trunk/library-asm/array.asm" +#line 59 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/array.asm" add hl, bc ; Adds current index @@ -264,7 +264,7 @@ ARRAY_END: push de exx -#line 92 "/src/zxb/trunk/library-asm/array.asm" +#line 92 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/array.asm" LOCAL ARRAY_SIZE_LOOP ex de, hl @@ -295,7 +295,7 @@ ARRAY_SIZE_LOOP: ;add hl, de ;__ARRAY_FIN: -#line 123 "/src/zxb/trunk/library-asm/array.asm" +#line 123 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/array.asm" pop de add hl, de ; Adds element start @@ -824,7 +824,7 @@ BRIGHT_TMP: -#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" +#line 4 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" @@ -883,7 +883,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" +#line 65 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -2147,9 +2147,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/src/zxb/trunk/library-asm/alloc.asm" +#line 111 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ret z ; NULL -#line 113 "/src/zxb/trunk/library-asm/alloc.asm" +#line 113 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -2333,6 +2333,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -2389,10 +2390,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/readbug.asm b/tests/functional/readbug.asm index 8e445fe5d..853a4b5e7 100644 --- a/tests/functional/readbug.asm +++ b/tests/functional/readbug.asm @@ -338,9 +338,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/src/zxb/trunk/library-asm/alloc.asm" +#line 111 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ret z ; NULL -#line 113 "/src/zxb/trunk/library-asm/alloc.asm" +#line 113 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -554,6 +554,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -610,10 +611,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/readokdown.asm b/tests/functional/readokdown.asm index 37686008d..87d8a4875 100644 --- a/tests/functional/readokdown.asm +++ b/tests/functional/readokdown.asm @@ -462,7 +462,7 @@ BRIGHT_TMP: -#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" +#line 4 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" @@ -521,7 +521,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" +#line 65 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -2460,9 +2460,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/src/zxb/trunk/library-asm/alloc.asm" +#line 111 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ret z ; NULL -#line 113 "/src/zxb/trunk/library-asm/alloc.asm" +#line 113 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -2644,6 +2644,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -2700,10 +2701,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/readokup.asm b/tests/functional/readokup.asm index cf0602341..1f11b134f 100644 --- a/tests/functional/readokup.asm +++ b/tests/functional/readokup.asm @@ -461,7 +461,7 @@ BRIGHT_TMP: -#line 4 "/src/zxb/trunk/library-asm/copy_attr.asm" +#line 4 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" @@ -520,7 +520,7 @@ TABLE: and (hl) ; OVER 2 MODE or (hl) ; OVER 3 MODE -#line 65 "/src/zxb/trunk/library-asm/copy_attr.asm" +#line 65 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/copy_attr.asm" __REFRESH_TMP: ld a, (hl) @@ -2459,9 +2459,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/src/zxb/trunk/library-asm/alloc.asm" +#line 111 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ret z ; NULL -#line 113 "/src/zxb/trunk/library-asm/alloc.asm" +#line 113 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -2643,6 +2643,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -2699,10 +2700,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/strsigil.asm b/tests/functional/strsigil.asm index b0771cd7e..e732a4ce3 100644 --- a/tests/functional/strsigil.asm +++ b/tests/functional/strsigil.asm @@ -444,6 +444,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -500,10 +501,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP @@ -700,9 +717,9 @@ __MEM_START: __MEM_LOOP: ; Loads lengh at (HL, HL+). If Lenght >= BC, jump to __MEM_DONE ld a, h ; HL = NULL (No memory available?) or l -#line 111 "/src/zxb/trunk/library-asm/alloc.asm" +#line 111 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ret z ; NULL -#line 113 "/src/zxb/trunk/library-asm/alloc.asm" +#line 113 "/Users/boriel/Documents/src/zxbasic/zxbasic/library-asm/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl diff --git a/tests/functional/test.py b/tests/functional/test.py index 30932ac5b..84e2359e5 100755 --- a/tests/functional/test.py +++ b/tests/functional/test.py @@ -454,7 +454,7 @@ def normalizeDiff(diff): is_same_file(fname1, tfname, ignore_regexp=FILTER, diff=lines) lines = normalizeDiff(lines) - if lines != fdiff: + if lines[:len(fdiff)] != fdiff: for x, y in zip(lines, fdiff): x = x.strip() y = y.strip() @@ -509,8 +509,7 @@ def main(argv=None): parser.add_argument('-d', '--show-diff', action='store_true', help='Shows output difference on failure') parser.add_argument('-v', '--show-visual-diff', action='store_true', help='Shows visual difference using vimdiff ' 'upon failure') - parser.add_argument('-u', '--update', type=str, default=None, help='Updates all *.bas test if the UPDATE diff' - ' matches') + parser.add_argument('-u', '--update', type=str, default=None, help='Updates a test if the UPDATE diff matches') parser.add_argument('-U', '--force-update', action='store_true', help='Updates all failed test with the new output') parser.add_argument('--tmp-dir', type=str, default=TEMP_DIR, help='Temporary directory for tests generation') parser.add_argument('FILES', nargs='+', type=str, help='List of files to be processed') diff --git a/tests/functional/while.asm b/tests/functional/while.asm index dc9efd8e7..e7a34d56a 100644 --- a/tests/functional/while.asm +++ b/tests/functional/while.asm @@ -186,6 +186,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -242,10 +243,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP diff --git a/tests/functional/whilesplitted.asm b/tests/functional/whilesplitted.asm index 2a6d45bfb..701b8dfc0 100644 --- a/tests/functional/whilesplitted.asm +++ b/tests/functional/whilesplitted.asm @@ -188,6 +188,7 @@ __FTOU32REG: ; Converts a Float to (un)signed 32 bit integer (NOTE: It's ALWAYS PROC LOCAL __IS_FLOAT + LOCAL __NEGATE or a jr nz, __IS_FLOAT @@ -244,10 +245,26 @@ __FTOU32REG_LOOP: __FTOU32REG_END: pop af ; Take the sign bit or a ; Sets SGN bit to 1 if negative - jp m, __NEG32 ; Negates DEHL + jp m, __NEGATE ; Negates DEHL ret +__NEGATE: + exx + ld a, d + or e + or b + or c + exx + jr z, __END + inc l + jr nz, __END + inc h + jr nz, __END + inc de + LOCAL __END +__END: + jp __NEG32 ENDP From dcf29a55cceffaecf7c3c2dcab81a0c6d5f24bf1 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 23 Nov 2018 00:12:39 +0100 Subject: [PATCH 245/247] =?UTF-8?q?Bump=20version:=201.8.8=20=E2=86=92=201?= =?UTF-8?q?.8.9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- ChangeLog | 6 ++++++ version.py | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index d0decb5e0..486c4c846 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,4 +1,4 @@ [bumpversion] -current_version = 1.8.8 +current_version = 1.8.9 files = version.py diff --git a/ChangeLog b/ChangeLog index 3c036768e..f2ed395ad 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +================================================================ +Changes from Version 1.8.8 to 1.8.9 +! Bugfix: Crash in READ and DATA sentences under some cases +! Bugfix: Fix INT to behave like the original one (Round to -INF) +! Bugfix: --array-check was not working properly. Fixed! + ================================================================ Changes from Version 1.8.7 to 1.8.8 ! Bugfix: fix 32 bit operations (DIV, MOD...) diff --git a/version.py b/version.py index dfa1796c7..051375da4 100755 --- a/version.py +++ b/version.py @@ -1 +1 @@ -VERSION = '1.8.8' +VERSION = '1.8.9' From bc9de5643aa2a861b12d952b8e102dda11415e9d Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Fri, 8 Mar 2019 00:32:56 +0100 Subject: [PATCH 246/247] Fix error on multiple ORG When using ORG several times, if the assembled regions overlaps, sometimes declaring a label on top of an existing (assembled) instruction crashed the ASM. Fixed. --- asmparse.py | 1 - tests/functional/orgasm.asm | 15 +++++++++++++++ tests/functional/orgasm.bin | Bin 0 -> 8 bytes 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 tests/functional/orgasm.asm create mode 100644 tests/functional/orgasm.bin diff --git a/asmparse.py b/asmparse.py index 934422842..045a66c58 100755 --- a/asmparse.py +++ b/asmparse.py @@ -525,7 +525,6 @@ def declare_label(self, label, lineno, value=None, local=False, namespace=None): self.local_labels[-1][ex_label] = Label(ex_label, lineno, value, local, namespace, is_address) self.set_memory_slot() - self.memory_bytes[self.org] += ('%s:' % ex_label,) return self.local_labels[-1][ex_label] diff --git a/tests/functional/orgasm.asm b/tests/functional/orgasm.asm new file mode 100644 index 000000000..20137aebe --- /dev/null +++ b/tests/functional/orgasm.asm @@ -0,0 +1,15 @@ + org 32768 +__START_PROGRAM: + di + exx + ld hl, 0 + + ;org 32768 + halt + halt + +__END_PROGRAM: +__END_PERA: + nop +__ENDPINA: + END diff --git a/tests/functional/orgasm.bin b/tests/functional/orgasm.bin new file mode 100644 index 0000000000000000000000000000000000000000..bee12b0d09d61c55c04dd16af429c280fd756012 GIT binary patch literal 8 Pcmex-Q;~t8tc(Ew5TgRx literal 0 HcmV?d00001 From 3e76ad5b5d9e7e35ad2fcbf23fd8df90bfd0de25 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Wed, 3 Apr 2019 00:01:43 +0200 Subject: [PATCH 247/247] Follow flake8 to pass tests --- arch/zx48k/backend/__16bit.py | 30 ++++++++++++++---------------- arch/zx48k/backend/__f16.py | 10 +++++----- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/arch/zx48k/backend/__16bit.py b/arch/zx48k/backend/__16bit.py index 6297503a4..f13c50daa 100644 --- a/arch/zx48k/backend/__16bit.py +++ b/arch/zx48k/backend/__16bit.py @@ -288,15 +288,14 @@ def _divu16(ins): ''' op1, op2 = tuple(ins.quad[2:]) if is_int(op1) and int(op1) == 0: # 0 / A = 0 + if op2[0] in ('_', '$'): + output = [] # Optimization: Discard previous op if not from the stack + else: + output = _16bit_oper(op2) # Normalize stack - if op2[0] in ('_', '$'): - output = [] # Optimization: Discard previous op if not from the stack - else: - output = _16bit_oper(op2) # Normalize stack - - output.append('ld hl, 0') - output.append('push hl') - return output + output.append('ld hl, 0') + output.append('push hl') + return output if is_int(op2): op = int16(op2) @@ -349,15 +348,14 @@ def _divi16(ins): ''' op1, op2 = tuple(ins.quad[2:]) if is_int(op1) and int(op1) == 0: # 0 / A = 0 + if op2[0] in ('_', '$'): + output = [] # Optimization: Discard previous op if not from the stack + else: + output = _16bit_oper(op2) # Normalize stack - if op2[0] in ('_', '$'): - output = [] # Optimization: Discard previous op if not from the stack - else: - output = _16bit_oper(op2) # Normalize stack - - output.append('ld hl, 0') - output.append('push hl') - return output + output.append('ld hl, 0') + output.append('push hl') + return output if is_int(op2): op = int16(op2) diff --git a/arch/zx48k/backend/__f16.py b/arch/zx48k/backend/__f16.py index 6090edcbd..668c6f0ce 100644 --- a/arch/zx48k/backend/__f16.py +++ b/arch/zx48k/backend/__f16.py @@ -304,11 +304,11 @@ def _modf16(ins): op1, op2 = tuple(ins.quad[2:]) if is_float(op2) and float(op2) == 1: - output = _f16_oper(op1) - output.append('ld hl, 0') - output.append('push hl') - output.append('push hl') - return output + output = _f16_oper(op1) + output.append('ld hl, 0') + output.append('push hl') + output.append('push hl') + return output rev = not is_float(op1) and op1[0] != 't' and op2[0] == 't'