From dc92d75464dcdeb4a3029a1218277de953c1ead3 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 30 Mar 2025 23:30:57 +0200 Subject: [PATCH 1/4] refact: move mem runtime routines to mem/ folder --- src/arch/z80/backend/common.py | 3 +- src/arch/z80/backend/runtime/core.py | 2 +- src/arch/z80/optimizer/cpustate.py | 6 +- .../arch/zx48k/runtime/array/arrayalloc.asm | 2 +- .../arch/zx48k/runtime/array/arraystrfree.asm | 2 +- src/lib/arch/zx48k/runtime/asc.asm | 2 +- src/lib/arch/zx48k/runtime/chr.asm | 3 +- .../arch/zx48k/runtime/io/keyboard/inkey.asm | 2 +- src/lib/arch/zx48k/runtime/letsubstr.asm | 3 +- src/lib/arch/zx48k/runtime/load.asm | 2 +- src/lib/arch/zx48k/runtime/loadstr.asm | 2 +- .../arch/zx48k/runtime/{ => mem}/alloc.asm | 0 .../arch/zx48k/runtime/{ => mem}/calloc.asm | 2 +- src/lib/arch/zx48k/runtime/{ => mem}/free.asm | 0 .../arch/zx48k/runtime/{ => mem}/realloc.asm | 5 +- src/lib/arch/zx48k/runtime/printstr.asm | 3 +- src/lib/arch/zx48k/runtime/read_restore.asm | 2 +- src/lib/arch/zx48k/runtime/save.asm | 2 +- src/lib/arch/zx48k/runtime/storestr2.asm | 3 +- src/lib/arch/zx48k/runtime/str.asm | 3 +- src/lib/arch/zx48k/runtime/strcat.asm | 3 +- src/lib/arch/zx48k/runtime/strcpy.asm | 3 +- src/lib/arch/zx48k/runtime/string.asm | 2 +- src/lib/arch/zx48k/runtime/strslice.asm | 5 +- src/lib/arch/zx48k/runtime/usr_str.asm | 2 +- src/lib/arch/zx48k/runtime/val.asm | 3 +- src/lib/arch/zx48k/stdlib/alloc.bas | 10 +- src/lib/arch/zx48k/stdlib/hex.bas | 2 +- src/lib/arch/zx48k/stdlib/screen.bas | 4 +- src/lib/arch/zx48k/stdlib/spectranet.bas | 2 +- .../arch/zxnext/runtime/array/arrayalloc.asm | 2 +- .../zxnext/runtime/array/arraystrfree.asm | 2 +- src/lib/arch/zxnext/runtime/asc.asm | 2 +- src/lib/arch/zxnext/runtime/chr.asm | 3 +- .../arch/zxnext/runtime/io/keyboard/inkey.asm | 2 +- src/lib/arch/zxnext/runtime/letsubstr.asm | 3 +- src/lib/arch/zxnext/runtime/load.asm | 2 +- src/lib/arch/zxnext/runtime/loadstr.asm | 2 +- .../arch/zxnext/runtime/{ => mem}/alloc.asm | 0 .../arch/zxnext/runtime/{ => mem}/calloc.asm | 2 +- .../arch/zxnext/runtime/{ => mem}/free.asm | 0 .../arch/zxnext/runtime/{ => mem}/realloc.asm | 5 +- src/lib/arch/zxnext/runtime/printstr.asm | 3 +- src/lib/arch/zxnext/runtime/read_restore.asm | 2 +- src/lib/arch/zxnext/runtime/save.asm | 2 +- src/lib/arch/zxnext/runtime/storestr2.asm | 3 +- src/lib/arch/zxnext/runtime/str.asm | 3 +- src/lib/arch/zxnext/runtime/strcat.asm | 3 +- src/lib/arch/zxnext/runtime/strcpy.asm | 3 +- src/lib/arch/zxnext/runtime/string.asm | 2 +- src/lib/arch/zxnext/runtime/strslice.asm | 5 +- src/lib/arch/zxnext/runtime/usr_str.asm | 2 +- src/lib/arch/zxnext/runtime/val.asm | 3 +- src/lib/arch/zxnext/stdlib/alloc.bas | 10 +- src/lib/arch/zxnext/stdlib/hex.bas | 2 +- src/lib/arch/zxnext/stdlib/screen.bas | 4 +- src/lib/arch/zxnext/stdlib/spectranet.bas | 2 +- src/zxbasm/memory.py | 6 +- .../arch/zx48k/cast_f16_to_param.asm | 54 +- tests/functional/arch/zx48k/emptystrparam.asm | 404 ++++++------ tests/functional/arch/zx48k/lcd3.asm | 614 +++++++++--------- tests/functional/arch/zx48k/lcd7.asm | 406 ++++++------ tests/functional/arch/zx48k/lcd8.asm | 404 ++++++------ tests/functional/arch/zx48k/lcd9.asm | 406 ++++++------ 64 files changed, 1216 insertions(+), 1237 deletions(-) rename src/lib/arch/zx48k/runtime/{ => mem}/alloc.asm (100%) rename src/lib/arch/zx48k/runtime/{ => mem}/calloc.asm (97%) rename src/lib/arch/zx48k/runtime/{ => mem}/free.asm (100%) rename src/lib/arch/zx48k/runtime/{ => mem}/realloc.asm (98%) rename src/lib/arch/zxnext/runtime/{ => mem}/alloc.asm (100%) rename src/lib/arch/zxnext/runtime/{ => mem}/calloc.asm (97%) rename src/lib/arch/zxnext/runtime/{ => mem}/free.asm (100%) rename src/lib/arch/zxnext/runtime/{ => mem}/realloc.asm (98%) diff --git a/src/arch/z80/backend/common.py b/src/arch/z80/backend/common.py index a0af28828..363dfdc0a 100644 --- a/src/arch/z80/backend/common.py +++ b/src/arch/z80/backend/common.py @@ -7,13 +7,12 @@ from src.api import global_, tmp_labels from src.api.config import OPTIONS, OptimizationStrategy from src.api.exception import TempAlreadyFreedError - from .runtime import LABEL_REQUIRED_MODULES, NAMESPACE, RUNTIME_LABELS from .runtime import Labels as RuntimeLabel # List of modules (in alphabetical order) that, if included, should call MEM_INIT MEMINITS = { - "alloc.asm", + "mem/alloc.asm", "loadstr.asm", "storestr2.asm", "storestr.asm", diff --git a/src/arch/z80/backend/runtime/core.py b/src/arch/z80/backend/runtime/core.py index 0477e0a92..3dbd2780d 100644 --- a/src/arch/z80/backend/runtime/core.py +++ b/src/arch/z80/backend/runtime/core.py @@ -195,7 +195,7 @@ class CoreLabels: CoreLabels.LTI16: "cmp/lti16.asm", CoreLabels.LTI8: "cmp/lti8.asm", CoreLabels.LTI32: "cmp/lti32.asm", - CoreLabels.MEM_FREE: "free.asm", + CoreLabels.MEM_FREE: "mem/free.asm", CoreLabels.MODF: "arith/modf.asm", CoreLabels.MODF16: "arith/modf16.asm", CoreLabels.MODI16: "arith/div16.asm", diff --git a/src/arch/z80/optimizer/cpustate.py b/src/arch/z80/optimizer/cpustate.py index 8e845a533..d30206a89 100644 --- a/src/arch/z80/optimizer/cpustate.py +++ b/src/arch/z80/optimizer/cpustate.py @@ -410,9 +410,9 @@ def set(self, r: str, val: int | str | None) -> None: if is_unknown8(val): val = f"{new_tmp_val()}{HL_SEP}{val}" - assert is_num or is_unknown16(val) or is_label(val), ( - f"val '{val}' is neither a number, nor a label nor an unknown16" - ) + assert ( + is_num or is_unknown16(val) or is_label(val) + ), f"val '{val}' is neither a number, nor a label nor an unknown16" self.regs[r] = val if is_16bit_composed_register(r): # sp register is not included. Special case diff --git a/src/lib/arch/zx48k/runtime/array/arrayalloc.asm b/src/lib/arch/zx48k/runtime/array/arrayalloc.asm index 04f593249..705efe67b 100644 --- a/src/lib/arch/zx48k/runtime/array/arrayalloc.asm +++ b/src/lib/arch/zx48k/runtime/array/arrayalloc.asm @@ -1,5 +1,5 @@ -#include once +#include once ; --------------------------------------------------------------------- diff --git a/src/lib/arch/zx48k/runtime/array/arraystrfree.asm b/src/lib/arch/zx48k/runtime/array/arraystrfree.asm index bac81e816..c599ef6b7 100644 --- a/src/lib/arch/zx48k/runtime/array/arraystrfree.asm +++ b/src/lib/arch/zx48k/runtime/array/arraystrfree.asm @@ -2,7 +2,7 @@ ; HL = Pointer to start of array in memory ; Top of the stack = Number of elements of the array -#include once +#include once push namespace core diff --git a/src/lib/arch/zx48k/runtime/asc.asm b/src/lib/arch/zx48k/runtime/asc.asm index e36962e9c..91f98fc2c 100644 --- a/src/lib/arch/zx48k/runtime/asc.asm +++ b/src/lib/arch/zx48k/runtime/asc.asm @@ -1,5 +1,5 @@ ; Returns the ascii code for the given str -#include once +#include once push namespace core diff --git a/src/lib/arch/zx48k/runtime/chr.asm b/src/lib/arch/zx48k/runtime/chr.asm index b6709d146..494285dc8 100644 --- a/src/lib/arch/zx48k/runtime/chr.asm +++ b/src/lib/arch/zx48k/runtime/chr.asm @@ -1,7 +1,7 @@ ; CHR$(x, y, x) returns the string CHR$(x) + CHR$(y) + CHR$(z) ; -#include once +#include once push namespace core @@ -76,4 +76,3 @@ __CHR_END: ENDP pop namespace - diff --git a/src/lib/arch/zx48k/runtime/io/keyboard/inkey.asm b/src/lib/arch/zx48k/runtime/io/keyboard/inkey.asm index 390be8ffe..8ab774f8b 100644 --- a/src/lib/arch/zx48k/runtime/io/keyboard/inkey.asm +++ b/src/lib/arch/zx48k/runtime/io/keyboard/inkey.asm @@ -3,7 +3,7 @@ ; containing the string. ; An empty string otherwise. -#include once +#include once push namespace core diff --git a/src/lib/arch/zx48k/runtime/letsubstr.asm b/src/lib/arch/zx48k/runtime/letsubstr.asm index 6ce63a51f..4a0a3e7f6 100644 --- a/src/lib/arch/zx48k/runtime/letsubstr.asm +++ b/src/lib/arch/zx48k/runtime/letsubstr.asm @@ -7,7 +7,7 @@ ; => Not 0 if HL must be freed from memory on exit ; TOP -3 B$ address -#include once +#include once push namespace core @@ -155,4 +155,3 @@ __FREE_STR: ENDP pop namespace - diff --git a/src/lib/arch/zx48k/runtime/load.asm b/src/lib/arch/zx48k/runtime/load.asm index 0da9db990..ce6e97733 100644 --- a/src/lib/arch/zx48k/runtime/load.asm +++ b/src/lib/arch/zx48k/runtime/load.asm @@ -1,4 +1,4 @@ -#include once +#include once #ifndef HIDE_LOAD_MSG # include once diff --git a/src/lib/arch/zx48k/runtime/loadstr.asm b/src/lib/arch/zx48k/runtime/loadstr.asm index 168bf72d8..ae597951f 100644 --- a/src/lib/arch/zx48k/runtime/loadstr.asm +++ b/src/lib/arch/zx48k/runtime/loadstr.asm @@ -1,4 +1,4 @@ -#include once +#include once ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again diff --git a/src/lib/arch/zx48k/runtime/alloc.asm b/src/lib/arch/zx48k/runtime/mem/alloc.asm similarity index 100% rename from src/lib/arch/zx48k/runtime/alloc.asm rename to src/lib/arch/zx48k/runtime/mem/alloc.asm diff --git a/src/lib/arch/zx48k/runtime/calloc.asm b/src/lib/arch/zx48k/runtime/mem/calloc.asm similarity index 97% rename from src/lib/arch/zx48k/runtime/calloc.asm rename to src/lib/arch/zx48k/runtime/mem/calloc.asm index e069eecd2..fbda2cb17 100644 --- a/src/lib/arch/zx48k/runtime/calloc.asm +++ b/src/lib/arch/zx48k/runtime/mem/calloc.asm @@ -9,7 +9,7 @@ ; ; Please read the MIT license on the internet -#include once +#include once ; --------------------------------------------------------------------- diff --git a/src/lib/arch/zx48k/runtime/free.asm b/src/lib/arch/zx48k/runtime/mem/free.asm similarity index 100% rename from src/lib/arch/zx48k/runtime/free.asm rename to src/lib/arch/zx48k/runtime/mem/free.asm diff --git a/src/lib/arch/zx48k/runtime/realloc.asm b/src/lib/arch/zx48k/runtime/mem/realloc.asm similarity index 98% rename from src/lib/arch/zx48k/runtime/realloc.asm rename to src/lib/arch/zx48k/runtime/mem/realloc.asm index e5c803d34..01e832fdb 100644 --- a/src/lib/arch/zx48k/runtime/realloc.asm +++ b/src/lib/arch/zx48k/runtime/mem/realloc.asm @@ -67,8 +67,8 @@ #include once -#include once -#include once +#include once +#include once ; --------------------------------------------------------------------- @@ -158,4 +158,3 @@ __REALLOC_END: ENDP pop namespace - diff --git a/src/lib/arch/zx48k/runtime/printstr.asm b/src/lib/arch/zx48k/runtime/printstr.asm index d680e8646..808e31878 100644 --- a/src/lib/arch/zx48k/runtime/printstr.asm +++ b/src/lib/arch/zx48k/runtime/printstr.asm @@ -1,7 +1,7 @@ #include once #include once #include once -#include once +#include once ; PRINT command routine ; Prints string pointed by HL @@ -57,4 +57,3 @@ __PRINT_STR: ENDP pop namespace - diff --git a/src/lib/arch/zx48k/runtime/read_restore.asm b/src/lib/arch/zx48k/runtime/read_restore.asm index 2876a97a6..f97bc97f0 100644 --- a/src/lib/arch/zx48k/runtime/read_restore.asm +++ b/src/lib/arch/zx48k/runtime/read_restore.asm @@ -25,7 +25,7 @@ #include once #include once #include once -#include once +#include once #define _str 1 #define _i8 2 diff --git a/src/lib/arch/zx48k/runtime/save.asm b/src/lib/arch/zx48k/runtime/save.asm index 98c6f4ce3..791088bab 100644 --- a/src/lib/arch/zx48k/runtime/save.asm +++ b/src/lib/arch/zx48k/runtime/save.asm @@ -4,7 +4,7 @@ ; YYY and ZZZ are 16 bit on top of the stack. #include once -#include once +#include once push namespace core diff --git a/src/lib/arch/zx48k/runtime/storestr2.asm b/src/lib/arch/zx48k/runtime/storestr2.asm index b652f3194..343d2c4a6 100644 --- a/src/lib/arch/zx48k/runtime/storestr2.asm +++ b/src/lib/arch/zx48k/runtime/storestr2.asm @@ -5,7 +5,7 @@ ; DE = address of 2n string. It just copies DE into (HL) ; freeing (HL) previously. -#include once +#include once push namespace core @@ -40,4 +40,3 @@ __STORE_STR2: ret pop namespace - diff --git a/src/lib/arch/zx48k/runtime/str.asm b/src/lib/arch/zx48k/runtime/str.asm index 1e5e306b5..a3cc9b8d1 100644 --- a/src/lib/arch/zx48k/runtime/str.asm +++ b/src/lib/arch/zx48k/runtime/str.asm @@ -4,7 +4,7 @@ ; Returns a pointer (in HL) to the memory heap ; containing the FP number string representation -#include once +#include once #include once #include once @@ -78,4 +78,3 @@ STK_END EQU 5C65h ENDP pop namespace - diff --git a/src/lib/arch/zx48k/runtime/strcat.asm b/src/lib/arch/zx48k/runtime/strcat.asm index 8a3a4c7de..1d1ed1829 100644 --- a/src/lib/arch/zx48k/runtime/strcat.asm +++ b/src/lib/arch/zx48k/runtime/strcat.asm @@ -1,4 +1,4 @@ -#include once +#include once #include once push namespace core @@ -127,4 +127,3 @@ __STRCATEND: ENDP pop namespace - diff --git a/src/lib/arch/zx48k/runtime/strcpy.asm b/src/lib/arch/zx48k/runtime/strcpy.asm index 091e2e11c..d864623d2 100644 --- a/src/lib/arch/zx48k/runtime/strcpy.asm +++ b/src/lib/arch/zx48k/runtime/strcpy.asm @@ -1,4 +1,4 @@ -#include once +#include once ; String library @@ -97,4 +97,3 @@ __NOTHING_TO_COPY: ENDP pop namespace - diff --git a/src/lib/arch/zx48k/runtime/string.asm b/src/lib/arch/zx48k/runtime/string.asm index 31321ea7b..97a51894d 100644 --- a/src/lib/arch/zx48k/runtime/string.asm +++ b/src/lib/arch/zx48k/runtime/string.asm @@ -1,6 +1,6 @@ ; String library -#include once +#include once #include once push namespace core diff --git a/src/lib/arch/zx48k/runtime/strslice.asm b/src/lib/arch/zx48k/runtime/strslice.asm index ec1b12b95..c63ad4e47 100644 --- a/src/lib/arch/zx48k/runtime/strslice.asm +++ b/src/lib/arch/zx48k/runtime/strslice.asm @@ -15,8 +15,8 @@ ; #include once -#include once -#include once +#include once +#include once push namespace core @@ -107,4 +107,3 @@ __FREE_ON_EXIT: ENDP pop namespace - diff --git a/src/lib/arch/zx48k/runtime/usr_str.asm b/src/lib/arch/zx48k/runtime/usr_str.asm index a2b047b9e..2753397fa 100644 --- a/src/lib/arch/zx48k/runtime/usr_str.asm +++ b/src/lib/arch/zx48k/runtime/usr_str.asm @@ -7,7 +7,7 @@ #include once #include once -#include once +#include once push namespace core diff --git a/src/lib/arch/zx48k/runtime/val.asm b/src/lib/arch/zx48k/runtime/val.asm index 22d9590a1..988b06907 100644 --- a/src/lib/arch/zx48k/runtime/val.asm +++ b/src/lib/arch/zx48k/runtime/val.asm @@ -1,4 +1,4 @@ -#include once +#include once #include once #include once @@ -118,4 +118,3 @@ __RET_ZERO: ; Returns 0 Floating point on error ENDP pop namespace - diff --git a/src/lib/arch/zx48k/stdlib/alloc.bas b/src/lib/arch/zx48k/stdlib/alloc.bas index afe27d50d..acb561163 100644 --- a/src/lib/arch/zx48k/stdlib/alloc.bas +++ b/src/lib/arch/zx48k/stdlib/alloc.bas @@ -230,9 +230,9 @@ end function #pragma pop(case_insensitive) -#require "alloc.asm" -#require "free.asm" -#require "realloc.asm" -#require "calloc.asm" +#require "mem/alloc.asm" +#require "mem/free.asm" +#require "mem/realloc.asm" +#require "mem/calloc.asm" -#endif \ No newline at end of file +#endif diff --git a/src/lib/arch/zx48k/stdlib/hex.bas b/src/lib/arch/zx48k/stdlib/hex.bas index 463a88676..be29fea23 100644 --- a/src/lib/arch/zx48k/stdlib/hex.bas +++ b/src/lib/arch/zx48k/stdlib/hex.bas @@ -112,6 +112,6 @@ end function #pragma pop(case_insensitive) ' The following is required to allocate dynamic memory for strings -#require "alloc.asm" +#require "mem/alloc.asm" #endif diff --git a/src/lib/arch/zx48k/stdlib/screen.bas b/src/lib/arch/zx48k/stdlib/screen.bas index f6e9424fa..686671c83 100644 --- a/src/lib/arch/zx48k/stdlib/screen.bas +++ b/src/lib/arch/zx48k/stdlib/screen.bas @@ -97,9 +97,9 @@ end function ' The following is required to allocate dynamic memory for strings -#require "alloc.asm" +#require "mem/alloc.asm" ' The following is required to manipulate the FP-CALC stack #require "stackf.asm" -#endif \ No newline at end of file +#endif diff --git a/src/lib/arch/zx48k/stdlib/spectranet.bas b/src/lib/arch/zx48k/stdlib/spectranet.bas index 563f20bcd..f8a67dab7 100644 --- a/src/lib/arch/zx48k/stdlib/spectranet.bas +++ b/src/lib/arch/zx48k/stdlib/spectranet.bas @@ -427,7 +427,7 @@ End Function #undef ERR_NR #require "spectranet.inc" -#require "free.asm" +#require "mem/free.asm" #pragma pop(case_insensitive) #endif diff --git a/src/lib/arch/zxnext/runtime/array/arrayalloc.asm b/src/lib/arch/zxnext/runtime/array/arrayalloc.asm index 04f593249..705efe67b 100644 --- a/src/lib/arch/zxnext/runtime/array/arrayalloc.asm +++ b/src/lib/arch/zxnext/runtime/array/arrayalloc.asm @@ -1,5 +1,5 @@ -#include once +#include once ; --------------------------------------------------------------------- diff --git a/src/lib/arch/zxnext/runtime/array/arraystrfree.asm b/src/lib/arch/zxnext/runtime/array/arraystrfree.asm index bac81e816..c599ef6b7 100644 --- a/src/lib/arch/zxnext/runtime/array/arraystrfree.asm +++ b/src/lib/arch/zxnext/runtime/array/arraystrfree.asm @@ -2,7 +2,7 @@ ; HL = Pointer to start of array in memory ; Top of the stack = Number of elements of the array -#include once +#include once push namespace core diff --git a/src/lib/arch/zxnext/runtime/asc.asm b/src/lib/arch/zxnext/runtime/asc.asm index e36962e9c..91f98fc2c 100644 --- a/src/lib/arch/zxnext/runtime/asc.asm +++ b/src/lib/arch/zxnext/runtime/asc.asm @@ -1,5 +1,5 @@ ; Returns the ascii code for the given str -#include once +#include once push namespace core diff --git a/src/lib/arch/zxnext/runtime/chr.asm b/src/lib/arch/zxnext/runtime/chr.asm index b6709d146..494285dc8 100644 --- a/src/lib/arch/zxnext/runtime/chr.asm +++ b/src/lib/arch/zxnext/runtime/chr.asm @@ -1,7 +1,7 @@ ; CHR$(x, y, x) returns the string CHR$(x) + CHR$(y) + CHR$(z) ; -#include once +#include once push namespace core @@ -76,4 +76,3 @@ __CHR_END: ENDP pop namespace - diff --git a/src/lib/arch/zxnext/runtime/io/keyboard/inkey.asm b/src/lib/arch/zxnext/runtime/io/keyboard/inkey.asm index 390be8ffe..8ab774f8b 100644 --- a/src/lib/arch/zxnext/runtime/io/keyboard/inkey.asm +++ b/src/lib/arch/zxnext/runtime/io/keyboard/inkey.asm @@ -3,7 +3,7 @@ ; containing the string. ; An empty string otherwise. -#include once +#include once push namespace core diff --git a/src/lib/arch/zxnext/runtime/letsubstr.asm b/src/lib/arch/zxnext/runtime/letsubstr.asm index 6ce63a51f..4a0a3e7f6 100644 --- a/src/lib/arch/zxnext/runtime/letsubstr.asm +++ b/src/lib/arch/zxnext/runtime/letsubstr.asm @@ -7,7 +7,7 @@ ; => Not 0 if HL must be freed from memory on exit ; TOP -3 B$ address -#include once +#include once push namespace core @@ -155,4 +155,3 @@ __FREE_STR: ENDP pop namespace - diff --git a/src/lib/arch/zxnext/runtime/load.asm b/src/lib/arch/zxnext/runtime/load.asm index 0da9db990..ce6e97733 100644 --- a/src/lib/arch/zxnext/runtime/load.asm +++ b/src/lib/arch/zxnext/runtime/load.asm @@ -1,4 +1,4 @@ -#include once +#include once #ifndef HIDE_LOAD_MSG # include once diff --git a/src/lib/arch/zxnext/runtime/loadstr.asm b/src/lib/arch/zxnext/runtime/loadstr.asm index 168bf72d8..ae597951f 100644 --- a/src/lib/arch/zxnext/runtime/loadstr.asm +++ b/src/lib/arch/zxnext/runtime/loadstr.asm @@ -1,4 +1,4 @@ -#include once +#include once ; Loads a string (ptr) from HL ; and duplicates it on dynamic memory again diff --git a/src/lib/arch/zxnext/runtime/alloc.asm b/src/lib/arch/zxnext/runtime/mem/alloc.asm similarity index 100% rename from src/lib/arch/zxnext/runtime/alloc.asm rename to src/lib/arch/zxnext/runtime/mem/alloc.asm diff --git a/src/lib/arch/zxnext/runtime/calloc.asm b/src/lib/arch/zxnext/runtime/mem/calloc.asm similarity index 97% rename from src/lib/arch/zxnext/runtime/calloc.asm rename to src/lib/arch/zxnext/runtime/mem/calloc.asm index e069eecd2..fbda2cb17 100644 --- a/src/lib/arch/zxnext/runtime/calloc.asm +++ b/src/lib/arch/zxnext/runtime/mem/calloc.asm @@ -9,7 +9,7 @@ ; ; Please read the MIT license on the internet -#include once +#include once ; --------------------------------------------------------------------- diff --git a/src/lib/arch/zxnext/runtime/free.asm b/src/lib/arch/zxnext/runtime/mem/free.asm similarity index 100% rename from src/lib/arch/zxnext/runtime/free.asm rename to src/lib/arch/zxnext/runtime/mem/free.asm diff --git a/src/lib/arch/zxnext/runtime/realloc.asm b/src/lib/arch/zxnext/runtime/mem/realloc.asm similarity index 98% rename from src/lib/arch/zxnext/runtime/realloc.asm rename to src/lib/arch/zxnext/runtime/mem/realloc.asm index e5c803d34..01e832fdb 100644 --- a/src/lib/arch/zxnext/runtime/realloc.asm +++ b/src/lib/arch/zxnext/runtime/mem/realloc.asm @@ -67,8 +67,8 @@ #include once -#include once -#include once +#include once +#include once ; --------------------------------------------------------------------- @@ -158,4 +158,3 @@ __REALLOC_END: ENDP pop namespace - diff --git a/src/lib/arch/zxnext/runtime/printstr.asm b/src/lib/arch/zxnext/runtime/printstr.asm index d680e8646..808e31878 100644 --- a/src/lib/arch/zxnext/runtime/printstr.asm +++ b/src/lib/arch/zxnext/runtime/printstr.asm @@ -1,7 +1,7 @@ #include once #include once #include once -#include once +#include once ; PRINT command routine ; Prints string pointed by HL @@ -57,4 +57,3 @@ __PRINT_STR: ENDP pop namespace - diff --git a/src/lib/arch/zxnext/runtime/read_restore.asm b/src/lib/arch/zxnext/runtime/read_restore.asm index 2876a97a6..f97bc97f0 100644 --- a/src/lib/arch/zxnext/runtime/read_restore.asm +++ b/src/lib/arch/zxnext/runtime/read_restore.asm @@ -25,7 +25,7 @@ #include once #include once #include once -#include once +#include once #define _str 1 #define _i8 2 diff --git a/src/lib/arch/zxnext/runtime/save.asm b/src/lib/arch/zxnext/runtime/save.asm index 98c6f4ce3..791088bab 100644 --- a/src/lib/arch/zxnext/runtime/save.asm +++ b/src/lib/arch/zxnext/runtime/save.asm @@ -4,7 +4,7 @@ ; YYY and ZZZ are 16 bit on top of the stack. #include once -#include once +#include once push namespace core diff --git a/src/lib/arch/zxnext/runtime/storestr2.asm b/src/lib/arch/zxnext/runtime/storestr2.asm index b652f3194..343d2c4a6 100644 --- a/src/lib/arch/zxnext/runtime/storestr2.asm +++ b/src/lib/arch/zxnext/runtime/storestr2.asm @@ -5,7 +5,7 @@ ; DE = address of 2n string. It just copies DE into (HL) ; freeing (HL) previously. -#include once +#include once push namespace core @@ -40,4 +40,3 @@ __STORE_STR2: ret pop namespace - diff --git a/src/lib/arch/zxnext/runtime/str.asm b/src/lib/arch/zxnext/runtime/str.asm index 1e5e306b5..a3cc9b8d1 100644 --- a/src/lib/arch/zxnext/runtime/str.asm +++ b/src/lib/arch/zxnext/runtime/str.asm @@ -4,7 +4,7 @@ ; Returns a pointer (in HL) to the memory heap ; containing the FP number string representation -#include once +#include once #include once #include once @@ -78,4 +78,3 @@ STK_END EQU 5C65h ENDP pop namespace - diff --git a/src/lib/arch/zxnext/runtime/strcat.asm b/src/lib/arch/zxnext/runtime/strcat.asm index 8a3a4c7de..1d1ed1829 100644 --- a/src/lib/arch/zxnext/runtime/strcat.asm +++ b/src/lib/arch/zxnext/runtime/strcat.asm @@ -1,4 +1,4 @@ -#include once +#include once #include once push namespace core @@ -127,4 +127,3 @@ __STRCATEND: ENDP pop namespace - diff --git a/src/lib/arch/zxnext/runtime/strcpy.asm b/src/lib/arch/zxnext/runtime/strcpy.asm index 091e2e11c..d864623d2 100644 --- a/src/lib/arch/zxnext/runtime/strcpy.asm +++ b/src/lib/arch/zxnext/runtime/strcpy.asm @@ -1,4 +1,4 @@ -#include once +#include once ; String library @@ -97,4 +97,3 @@ __NOTHING_TO_COPY: ENDP pop namespace - diff --git a/src/lib/arch/zxnext/runtime/string.asm b/src/lib/arch/zxnext/runtime/string.asm index 0631c2a85..0490ce185 100644 --- a/src/lib/arch/zxnext/runtime/string.asm +++ b/src/lib/arch/zxnext/runtime/string.asm @@ -1,6 +1,6 @@ ; String library -#include once +#include once #include once push namespace core diff --git a/src/lib/arch/zxnext/runtime/strslice.asm b/src/lib/arch/zxnext/runtime/strslice.asm index ec1b12b95..c63ad4e47 100644 --- a/src/lib/arch/zxnext/runtime/strslice.asm +++ b/src/lib/arch/zxnext/runtime/strslice.asm @@ -15,8 +15,8 @@ ; #include once -#include once -#include once +#include once +#include once push namespace core @@ -107,4 +107,3 @@ __FREE_ON_EXIT: ENDP pop namespace - diff --git a/src/lib/arch/zxnext/runtime/usr_str.asm b/src/lib/arch/zxnext/runtime/usr_str.asm index a2b047b9e..2753397fa 100644 --- a/src/lib/arch/zxnext/runtime/usr_str.asm +++ b/src/lib/arch/zxnext/runtime/usr_str.asm @@ -7,7 +7,7 @@ #include once #include once -#include once +#include once push namespace core diff --git a/src/lib/arch/zxnext/runtime/val.asm b/src/lib/arch/zxnext/runtime/val.asm index 22d9590a1..988b06907 100644 --- a/src/lib/arch/zxnext/runtime/val.asm +++ b/src/lib/arch/zxnext/runtime/val.asm @@ -1,4 +1,4 @@ -#include once +#include once #include once #include once @@ -118,4 +118,3 @@ __RET_ZERO: ; Returns 0 Floating point on error ENDP pop namespace - diff --git a/src/lib/arch/zxnext/stdlib/alloc.bas b/src/lib/arch/zxnext/stdlib/alloc.bas index afe27d50d..acb561163 100644 --- a/src/lib/arch/zxnext/stdlib/alloc.bas +++ b/src/lib/arch/zxnext/stdlib/alloc.bas @@ -230,9 +230,9 @@ end function #pragma pop(case_insensitive) -#require "alloc.asm" -#require "free.asm" -#require "realloc.asm" -#require "calloc.asm" +#require "mem/alloc.asm" +#require "mem/free.asm" +#require "mem/realloc.asm" +#require "mem/calloc.asm" -#endif \ No newline at end of file +#endif diff --git a/src/lib/arch/zxnext/stdlib/hex.bas b/src/lib/arch/zxnext/stdlib/hex.bas index 463a88676..be29fea23 100644 --- a/src/lib/arch/zxnext/stdlib/hex.bas +++ b/src/lib/arch/zxnext/stdlib/hex.bas @@ -112,6 +112,6 @@ end function #pragma pop(case_insensitive) ' The following is required to allocate dynamic memory for strings -#require "alloc.asm" +#require "mem/alloc.asm" #endif diff --git a/src/lib/arch/zxnext/stdlib/screen.bas b/src/lib/arch/zxnext/stdlib/screen.bas index f6e9424fa..686671c83 100644 --- a/src/lib/arch/zxnext/stdlib/screen.bas +++ b/src/lib/arch/zxnext/stdlib/screen.bas @@ -97,9 +97,9 @@ end function ' The following is required to allocate dynamic memory for strings -#require "alloc.asm" +#require "mem/alloc.asm" ' The following is required to manipulate the FP-CALC stack #require "stackf.asm" -#endif \ No newline at end of file +#endif diff --git a/src/lib/arch/zxnext/stdlib/spectranet.bas b/src/lib/arch/zxnext/stdlib/spectranet.bas index 563f20bcd..f8a67dab7 100644 --- a/src/lib/arch/zxnext/stdlib/spectranet.bas +++ b/src/lib/arch/zxnext/stdlib/spectranet.bas @@ -427,7 +427,7 @@ End Function #undef ERR_NR #require "spectranet.inc" -#require "free.asm" +#require "mem/free.asm" #pragma pop(case_insensitive) #endif diff --git a/src/zxbasm/memory.py b/src/zxbasm/memory.py index 4a1e0732a..1d83383c7 100644 --- a/src/zxbasm/memory.py +++ b/src/zxbasm/memory.py @@ -222,9 +222,9 @@ def declare_label( fname = gl.FILENAME if label.isdecimal(): # Temporary label? - assert not self._tmp_labels_lines[fname] or self._tmp_labels_lines[fname][-1] <= lineno, ( - "Temporary label out of order" - ) + assert ( + not self._tmp_labels_lines[fname] or self._tmp_labels_lines[fname][-1] <= lineno + ), "Temporary label out of order" if not self._tmp_labels_lines[fname] or self._tmp_labels_lines[fname][-1] != lineno: self._tmp_labels_lines[fname].append(lineno) diff --git a/tests/functional/arch/zx48k/cast_f16_to_param.asm b/tests/functional/arch/zx48k/cast_f16_to_param.asm index 46261cdee..8edfb1076 100644 --- a/tests/functional/arch/zx48k/cast_f16_to_param.asm +++ b/tests/functional/arch/zx48k/cast_f16_to_param.asm @@ -81,7 +81,7 @@ _gfxDrawLineClip.x.__LBOUND__: DEFW 0001h ;; --- end of user code --- #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/array/arrayalloc.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/calloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/calloc.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -92,7 +92,7 @@ _gfxDrawLineClip.x.__LBOUND__: ; closed source programs). ; ; Please read the MIT license on the internet -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -186,7 +186,7 @@ __STOP: ld (ERR_NR), a ret pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa @@ -294,7 +294,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -325,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -392,7 +392,7 @@ __MEM_SUBTRACT: ret ENDP pop namespace -#line 13 "/zxbasic/src/lib/arch/zx48k/runtime/calloc.asm" +#line 13 "/zxbasic/src/lib/arch/zx48k/runtime/mem/calloc.asm" ; --------------------------------------------------------------------- ; MEM_CALLOC ; Allocates a block of memory in the heap, and clears it filling it @@ -553,7 +553,26 @@ __ALLOC_INITIALIZED_LOCAL_ARRAY_WITH_BOUNDS: #line 142 "/zxbasic/src/lib/arch/zx48k/runtime/array/arrayalloc.asm" pop namespace #line 59 "arch/zx48k/cast_f16_to_param.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/iload32.asm" + ; __FASTCALL__ routine which + ; loads a 32 bits integer into DE,HL + ; stored at position pointed by POINTER HL + ; DE,HL <-- (HL) + push namespace core +__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 + pop namespace +#line 60 "arch/zx48k/cast_f16_to_param.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/free.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -711,25 +730,6 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ret ENDP pop namespace -#line 60 "arch/zx48k/cast_f16_to_param.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/iload32.asm" - ; __FASTCALL__ routine which - ; loads a 32 bits integer into DE,HL - ; stored at position pointed by POINTER HL - ; DE,HL <-- (HL) - push namespace core -__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 - pop namespace #line 61 "arch/zx48k/cast_f16_to_param.bas" .LABEL.__LABEL0: DEFB 00h diff --git a/tests/functional/arch/zx48k/emptystrparam.asm b/tests/functional/arch/zx48k/emptystrparam.asm index 5172abf9c..7e377c252 100644 --- a/tests/functional/arch/zx48k/emptystrparam.asm +++ b/tests/functional/arch/zx48k/emptystrparam.asm @@ -63,17 +63,18 @@ _stringtest__leave: .LABEL.__LABEL0: DEFW 0000h ;; --- end of user code --- -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; This ASM library is licensed under the MIT license ; you can use it for any purpose (even for commercial ; closed source programs). ; - ; Please read the BSD license on the internet + ; Please read the MIT license on the internet ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. ; Each free block contains this info: @@ -114,7 +115,7 @@ _stringtest__leave: ; | (0 if Size = 4)| ; +----------------+ ; When a block is FREED, the previous and next pointers are examined to see - ; if we can defragment the heap. If the block to be breed is just next to the + ; 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 @@ -123,6 +124,41 @@ _stringtest__leave: ; HL = BLOCK Start & DE = Length. ; An init directive is useful for initialization routines. ; They will be added automatically if needed. +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" + ; Simple error control routines +; vim:ts=4:et: + push namespace core + 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 + pop namespace +#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa @@ -230,202 +266,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/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 - ; --------------------------------------------------------------------- - push namespace core -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 - pop namespace -#line 42 "arch/zx48k/emptystrparam.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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 MIT license - ; you can use it for any purpose (even for commercial - ; closed source programs). - ; - ; Please read the MIT license 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 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" - ; Simple error control routines -; vim:ts=4:et: - push namespace core - 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 - pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -456,9 +297,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -560,5 +401,164 @@ __LOADSTR: ; __FASTCALL__ entry pop hl ; Recovers destiny in hl as result ret pop namespace +#line 42 "arch/zx48k/emptystrparam.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; --------------------------------------------------------------------- + push namespace core +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 + pop namespace #line 43 "arch/zx48k/emptystrparam.bas" END diff --git a/tests/functional/arch/zx48k/lcd3.asm b/tests/functional/arch/zx48k/lcd3.asm index 85ee705fb..749f52813 100644 --- a/tests/functional/arch/zx48k/lcd3.asm +++ b/tests/functional/arch/zx48k/lcd3.asm @@ -195,273 +195,6 @@ __ADDF: ; Addition jp __FPSTACK_POP pop namespace #line 111 "arch/zx48k/lcd3.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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 "/zxbasic/src/lib/arch/zx48k/runtime/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 - ; --------------------------------------------------------------------- - push namespace core -__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 - pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/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 - ; --------------------------------------------------------------------- - push namespace core -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 - pop namespace -#line 112 "arch/zx48k/lcd3.bas" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/ftou32reg.asm" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/neg32.asm" push namespace core @@ -560,19 +293,114 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A ld a, l ret pop namespace -#line 113 "arch/zx48k/lcd3.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 112 "arch/zx48k/lcd3.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 MIT license + ; you can use it for any purpose (even for commercial + ; closed source programs). + ; + ; Please read the MIT license 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 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" + ; Simple error control routines +; vim:ts=4:et: + push namespace core + 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 + pop namespace +#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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 MIT license + ; 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 MIT license on the internet + ; Please read the BSD license on the internet ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. ; Each free block contains this info: @@ -613,7 +441,7 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A ; | (0 if Size = 4)| ; +----------------+ ; When 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 + ; if we can defragment the heap. If the block to be breed is just next to the ; previous, or to the next (or both) they will be converted into a single ; block (so defragmented). ; MEMORY MANAGER @@ -622,41 +450,54 @@ __FTOU8: ; Converts float in C ED LH to Unsigned byte in A ; HL = BLOCK Start & DE = Length. ; An init directive is useful for initialization routines. ; They will be added automatically if needed. -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" - ; Simple error control routines -; vim:ts=4:et: + ; --------------------------------------------------------------------- + ; __MEM_INIT must be called to initalize this library with the + ; standard parameters + ; --------------------------------------------------------------------- push namespace core - 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 +__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 pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -687,9 +528,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -791,6 +632,165 @@ __LOADSTR: ; __FASTCALL__ entry pop hl ; Recovers destiny in hl as result ret pop namespace +#line 113 "arch/zx48k/lcd3.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; --------------------------------------------------------------------- + push namespace core +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 + pop namespace #line 114 "arch/zx48k/lcd3.bas" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/pstorestr2.asm" ; vim:ts=4:et:sw=4 diff --git a/tests/functional/arch/zx48k/lcd7.asm b/tests/functional/arch/zx48k/lcd7.asm index 44903fc6e..7f147793e 100644 --- a/tests/functional/arch/zx48k/lcd7.asm +++ b/tests/functional/arch/zx48k/lcd7.asm @@ -93,17 +93,18 @@ _Frame__leave: DEFB 4Fh DEFB 4Bh ;; --- end of user code --- -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; This ASM library is licensed under the MIT license ; you can use it for any purpose (even for commercial ; closed source programs). ; - ; Please read the BSD license on the internet + ; Please read the MIT license on the internet ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. ; Each free block contains this info: @@ -144,7 +145,7 @@ _Frame__leave: ; | (0 if Size = 4)| ; +----------------+ ; When a block is FREED, the previous and next pointers are examined to see - ; if we can defragment the heap. If the block to be breed is just next to the + ; 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 @@ -153,6 +154,41 @@ _Frame__leave: ; HL = BLOCK Start & DE = Length. ; An init directive is useful for initialization routines. ; They will be added automatically if needed. +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" + ; Simple error control routines +; vim:ts=4:et: + push namespace core + 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 + pop namespace +#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa @@ -260,202 +296,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/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 - ; --------------------------------------------------------------------- - push namespace core -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 - pop namespace -#line 70 "arch/zx48k/lcd7.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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 MIT license - ; you can use it for any purpose (even for commercial - ; closed source programs). - ; - ; Please read the MIT license 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 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" - ; Simple error control routines -; vim:ts=4:et: - push namespace core - 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 - pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -486,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -590,6 +431,165 @@ __LOADSTR: ; __FASTCALL__ entry pop hl ; Recovers destiny in hl as result ret pop namespace +#line 70 "arch/zx48k/lcd7.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; --------------------------------------------------------------------- + push namespace core +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 + pop namespace #line 71 "arch/zx48k/lcd7.bas" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/pstorestr.asm" ; vim:ts=4:et:sw=4 @@ -609,7 +609,7 @@ __LOADSTR: ; __FASTCALL__ entry ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/strcpy.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/realloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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/arch/zx48k/lcd8.asm b/tests/functional/arch/zx48k/lcd8.asm index 37eeed40e..7a87b34f5 100644 --- a/tests/functional/arch/zx48k/lcd8.asm +++ b/tests/functional/arch/zx48k/lcd8.asm @@ -95,17 +95,18 @@ _Frame__leave: DEFB 4Fh DEFB 4Bh ;; --- end of user code --- -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; This ASM library is licensed under the MIT license ; you can use it for any purpose (even for commercial ; closed source programs). ; - ; Please read the BSD license on the internet + ; Please read the MIT license on the internet ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. ; Each free block contains this info: @@ -146,7 +147,7 @@ _Frame__leave: ; | (0 if Size = 4)| ; +----------------+ ; When a block is FREED, the previous and next pointers are examined to see - ; if we can defragment the heap. If the block to be breed is just next to the + ; 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 @@ -155,6 +156,41 @@ _Frame__leave: ; HL = BLOCK Start & DE = Length. ; An init directive is useful for initialization routines. ; They will be added automatically if needed. +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" + ; Simple error control routines +; vim:ts=4:et: + push namespace core + 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 + pop namespace +#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa @@ -262,202 +298,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/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 - ; --------------------------------------------------------------------- - push namespace core -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 - pop namespace -#line 72 "arch/zx48k/lcd8.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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 MIT license - ; you can use it for any purpose (even for commercial - ; closed source programs). - ; - ; Please read the MIT license 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 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" - ; Simple error control routines -; vim:ts=4:et: - push namespace core - 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 - pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -488,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -592,6 +433,165 @@ __LOADSTR: ; __FASTCALL__ entry pop hl ; Recovers destiny in hl as result ret pop namespace +#line 72 "arch/zx48k/lcd8.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; --------------------------------------------------------------------- + push namespace core +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 + pop namespace #line 73 "arch/zx48k/lcd8.bas" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/strlen.asm" ; Returns len if a string diff --git a/tests/functional/arch/zx48k/lcd9.asm b/tests/functional/arch/zx48k/lcd9.asm index 620e27d29..599cf7f39 100644 --- a/tests/functional/arch/zx48k/lcd9.asm +++ b/tests/functional/arch/zx48k/lcd9.asm @@ -85,17 +85,18 @@ _Frame__leave: DEFB 4Fh DEFB 4Bh ;; --- end of user code --- -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; This ASM library is licensed under the MIT license ; you can use it for any purpose (even for commercial ; closed source programs). ; - ; Please read the BSD license on the internet + ; Please read the MIT license on the internet ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. ; Each free block contains this info: @@ -136,7 +137,7 @@ _Frame__leave: ; | (0 if Size = 4)| ; +----------------+ ; When a block is FREED, the previous and next pointers are examined to see - ; if we can defragment the heap. If the block to be breed is just next to the + ; 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 @@ -145,6 +146,41 @@ _Frame__leave: ; HL = BLOCK Start & DE = Length. ; An init directive is useful for initialization routines. ; They will be added automatically if needed. +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" + ; Simple error control routines +; vim:ts=4:et: + push namespace core + 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 + pop namespace +#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa @@ -252,202 +288,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/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 - ; --------------------------------------------------------------------- - push namespace core -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 - pop namespace -#line 60 "arch/zx48k/lcd9.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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 MIT license - ; you can use it for any purpose (even for commercial - ; closed source programs). - ; - ; Please read the MIT license 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 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" - ; Simple error control routines -; vim:ts=4:et: - push namespace core - 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 - pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -478,9 +319,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -582,6 +423,165 @@ __LOADSTR: ; __FASTCALL__ entry pop hl ; Recovers destiny in hl as result ret pop namespace +#line 60 "arch/zx48k/lcd9.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; --------------------------------------------------------------------- + push namespace core +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 + pop namespace #line 61 "arch/zx48k/lcd9.bas" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/storestr.asm" ; vim:ts=4:et:sw=4 @@ -595,7 +595,7 @@ __LOADSTR: ; __FASTCALL__ entry ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/strcpy.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/realloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/realloc.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) From d4a52ff3c5fe8095347e288979d52083eac36bc3 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 26 Apr 2025 11:20:38 +0200 Subject: [PATCH 2/4] refact: move memcopy.asm and heapinit.asm to runtime/mem folder --- src/lib/arch/zx48k/runtime/{ => mem}/heapinit.asm | 0 src/lib/arch/zx48k/runtime/{ => mem}/memcopy.asm | 0 src/lib/arch/zxnext/runtime/{ => mem}/heapinit.asm | 0 src/lib/arch/zxnext/runtime/{ => mem}/memcopy.asm | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename src/lib/arch/zx48k/runtime/{ => mem}/heapinit.asm (100%) rename src/lib/arch/zx48k/runtime/{ => mem}/memcopy.asm (100%) rename src/lib/arch/zxnext/runtime/{ => mem}/heapinit.asm (100%) rename src/lib/arch/zxnext/runtime/{ => mem}/memcopy.asm (100%) diff --git a/src/lib/arch/zx48k/runtime/heapinit.asm b/src/lib/arch/zx48k/runtime/mem/heapinit.asm similarity index 100% rename from src/lib/arch/zx48k/runtime/heapinit.asm rename to src/lib/arch/zx48k/runtime/mem/heapinit.asm diff --git a/src/lib/arch/zx48k/runtime/memcopy.asm b/src/lib/arch/zx48k/runtime/mem/memcopy.asm similarity index 100% rename from src/lib/arch/zx48k/runtime/memcopy.asm rename to src/lib/arch/zx48k/runtime/mem/memcopy.asm diff --git a/src/lib/arch/zxnext/runtime/heapinit.asm b/src/lib/arch/zxnext/runtime/mem/heapinit.asm similarity index 100% rename from src/lib/arch/zxnext/runtime/heapinit.asm rename to src/lib/arch/zxnext/runtime/mem/heapinit.asm diff --git a/src/lib/arch/zxnext/runtime/memcopy.asm b/src/lib/arch/zxnext/runtime/mem/memcopy.asm similarity index 100% rename from src/lib/arch/zxnext/runtime/memcopy.asm rename to src/lib/arch/zxnext/runtime/mem/memcopy.asm From 73137828e5698d71f499ce17d1b8c0b64b20bc89 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 26 Apr 2025 11:25:20 +0200 Subject: [PATCH 3/4] tests: update tests --- src/lib/arch/zx48k/runtime/mem/alloc.asm | 2 +- src/lib/arch/zx48k/runtime/mem/free.asm | 2 +- src/lib/arch/zx48k/stdlib/memcopy.bas | 2 +- src/lib/arch/zxnext/runtime/mem/alloc.asm | 2 +- src/lib/arch/zxnext/runtime/mem/free.asm | 2 +- src/lib/arch/zxnext/stdlib/memcopy.bas | 2 +- .../arch/zx48k/local_float_array0.asm | 74 ++-- .../arch/zx48k/local_float_array1.asm | 74 ++-- tests/functional/arch/zx48k/ltee1.asm | 408 ++++++++--------- tests/functional/arch/zx48k/ltee3.asm | 406 ++++++++--------- tests/functional/arch/zx48k/opt1_len.asm | 414 +++++++++--------- tests/functional/arch/zx48k/opt2_pstr.asm | 406 ++++++++--------- .../functional/arch/zx48k/optional_param4.asm | 406 ++++++++--------- tests/functional/arch/zx48k/param0.asm | 406 ++++++++--------- tests/functional/arch/zx48k/param2.asm | 406 ++++++++--------- tests/functional/arch/zx48k/paramstr3.asm | 406 ++++++++--------- tests/functional/arch/zx48k/paramstr4.asm | 406 ++++++++--------- tests/functional/arch/zx48k/paramstr5.asm | 406 ++++++++--------- tests/functional/arch/zx48k/slice2.asm | 336 +++++++------- tests/functional/arch/zx48k/stdlib_screen.asm | 90 ++-- tests/functional/arch/zx48k/storestr2.asm | 412 ++++++++--------- tests/functional/arch/zx48k/str_slash.asm | 408 ++++++++--------- tests/functional/arch/zx48k/stringfunc.asm | 408 ++++++++--------- tests/functional/arch/zx48k/stringparam.asm | 342 +++++++-------- tests/functional/arch/zx48k/strparam0.asm | 342 +++++++-------- tests/functional/arch/zx48k/strparam3.asm | 342 +++++++-------- tests/functional/arch/zx48k/valcrash1.asm | 408 ++++++++--------- tests/functional/zxbpp/prepro71.out | 8 +- 28 files changed, 3663 insertions(+), 3663 deletions(-) diff --git a/src/lib/arch/zx48k/runtime/mem/alloc.asm b/src/lib/arch/zx48k/runtime/mem/alloc.asm index fde6d1df4..2769745ab 100644 --- a/src/lib/arch/zx48k/runtime/mem/alloc.asm +++ b/src/lib/arch/zx48k/runtime/mem/alloc.asm @@ -66,7 +66,7 @@ ; They will be added automatically if needed. #include once -#include once +#include once ; --------------------------------------------------------------------- diff --git a/src/lib/arch/zx48k/runtime/mem/free.asm b/src/lib/arch/zx48k/runtime/mem/free.asm index 883e75b8d..171cbfa98 100644 --- a/src/lib/arch/zx48k/runtime/mem/free.asm +++ b/src/lib/arch/zx48k/runtime/mem/free.asm @@ -65,7 +65,7 @@ ; An init directive is useful for initialization routines. ; They will be added automatically if needed. -#include once +#include once ; --------------------------------------------------------------------- ; MEM_FREE diff --git a/src/lib/arch/zx48k/stdlib/memcopy.bas b/src/lib/arch/zx48k/stdlib/memcopy.bas index 4ddb18941..5a7942318 100644 --- a/src/lib/arch/zx48k/stdlib/memcopy.bas +++ b/src/lib/arch/zx48k/stdlib/memcopy.bas @@ -122,7 +122,7 @@ sub fastcall MemSet(dest as uinteger, value as ubyte, length as uinteger) end sub -#require "memcopy.asm" +#require "mem/memcopy.asm" #pragma pop(case_insensitive) diff --git a/src/lib/arch/zxnext/runtime/mem/alloc.asm b/src/lib/arch/zxnext/runtime/mem/alloc.asm index fde6d1df4..2769745ab 100644 --- a/src/lib/arch/zxnext/runtime/mem/alloc.asm +++ b/src/lib/arch/zxnext/runtime/mem/alloc.asm @@ -66,7 +66,7 @@ ; They will be added automatically if needed. #include once -#include once +#include once ; --------------------------------------------------------------------- diff --git a/src/lib/arch/zxnext/runtime/mem/free.asm b/src/lib/arch/zxnext/runtime/mem/free.asm index 883e75b8d..171cbfa98 100644 --- a/src/lib/arch/zxnext/runtime/mem/free.asm +++ b/src/lib/arch/zxnext/runtime/mem/free.asm @@ -65,7 +65,7 @@ ; An init directive is useful for initialization routines. ; They will be added automatically if needed. -#include once +#include once ; --------------------------------------------------------------------- ; MEM_FREE diff --git a/src/lib/arch/zxnext/stdlib/memcopy.bas b/src/lib/arch/zxnext/stdlib/memcopy.bas index 4ddb18941..5a7942318 100644 --- a/src/lib/arch/zxnext/stdlib/memcopy.bas +++ b/src/lib/arch/zxnext/stdlib/memcopy.bas @@ -122,7 +122,7 @@ sub fastcall MemSet(dest as uinteger, value as ubyte, length as uinteger) end sub -#require "memcopy.asm" +#require "mem/memcopy.asm" #pragma pop(case_insensitive) diff --git a/tests/functional/arch/zx48k/local_float_array0.asm b/tests/functional/arch/zx48k/local_float_array0.asm index 591a42d62..50aec5bf2 100644 --- a/tests/functional/arch/zx48k/local_float_array0.asm +++ b/tests/functional/arch/zx48k/local_float_array0.asm @@ -251,7 +251,7 @@ ARRAY_SIZE_LOOP: pop namespace #line 67 "arch/zx48k/local_float_array0.bas" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/array/arrayalloc.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/calloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/calloc.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -262,7 +262,7 @@ ARRAY_SIZE_LOOP: ; closed source programs). ; ; Please read the MIT license on the internet -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -356,8 +356,8 @@ __STOP: ld (ERR_NR), a ret pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" +#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -464,7 +464,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -495,9 +495,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -562,7 +562,7 @@ __MEM_SUBTRACT: ret ENDP pop namespace -#line 13 "/zxbasic/src/lib/arch/zx48k/runtime/calloc.asm" +#line 13 "/zxbasic/src/lib/arch/zx48k/runtime/mem/calloc.asm" ; --------------------------------------------------------------------- ; MEM_CALLOC ; Allocates a block of memory in the heap, and clears it filling it @@ -663,7 +663,35 @@ __ALLOC_INITIALIZED_LOCAL_ARRAY: #line 142 "/zxbasic/src/lib/arch/zx48k/runtime/array/arrayalloc.asm" pop namespace #line 68 "arch/zx48k/local_float_array0.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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)) + push namespace core +__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 + pop namespace +#line 69 "arch/zx48k/local_float_array0.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/free.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -821,34 +849,6 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ret ENDP pop namespace -#line 69 "arch/zx48k/local_float_array0.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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)) - push namespace core -__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 - pop namespace #line 70 "arch/zx48k/local_float_array0.bas" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/storef.asm" push namespace core diff --git a/tests/functional/arch/zx48k/local_float_array1.asm b/tests/functional/arch/zx48k/local_float_array1.asm index 8c12cd16a..60219fdc1 100644 --- a/tests/functional/arch/zx48k/local_float_array1.asm +++ b/tests/functional/arch/zx48k/local_float_array1.asm @@ -74,7 +74,7 @@ _test__leave: ret ;; --- end of user code --- #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/array/arrayalloc.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/calloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/calloc.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -85,7 +85,7 @@ _test__leave: ; closed source programs). ; ; Please read the MIT license on the internet -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -179,8 +179,8 @@ __STOP: ld (ERR_NR), a ret pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" +#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -287,7 +287,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -318,9 +318,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -385,7 +385,7 @@ __MEM_SUBTRACT: ret ENDP pop namespace -#line 13 "/zxbasic/src/lib/arch/zx48k/runtime/calloc.asm" +#line 13 "/zxbasic/src/lib/arch/zx48k/runtime/mem/calloc.asm" ; --------------------------------------------------------------------- ; MEM_CALLOC ; Allocates a block of memory in the heap, and clears it filling it @@ -486,7 +486,35 @@ __ALLOC_INITIALIZED_LOCAL_ARRAY: #line 142 "/zxbasic/src/lib/arch/zx48k/runtime/array/arrayalloc.asm" pop namespace #line 50 "arch/zx48k/local_float_array1.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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)) + push namespace core +__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 + pop namespace +#line 51 "arch/zx48k/local_float_array1.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/free.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -644,34 +672,6 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ret ENDP pop namespace -#line 51 "arch/zx48k/local_float_array1.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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)) - push namespace core -__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 - pop namespace #line 52 "arch/zx48k/local_float_array1.bas" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/storef.asm" push namespace core diff --git a/tests/functional/arch/zx48k/ltee1.asm b/tests/functional/arch/zx48k/ltee1.asm index 6ac2afc5a..d49e02c93 100644 --- a/tests/functional/arch/zx48k/ltee1.asm +++ b/tests/functional/arch/zx48k/ltee1.asm @@ -111,17 +111,18 @@ _addWibble__leave: DEFB 6Ch DEFB 65h ;; --- end of user code --- -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; This ASM library is licensed under the MIT license ; you can use it for any purpose (even for commercial ; closed source programs). ; - ; Please read the BSD license on the internet + ; Please read the MIT license on the internet ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. ; Each free block contains this info: @@ -162,7 +163,7 @@ _addWibble__leave: ; | (0 if Size = 4)| ; +----------------+ ; When a block is FREED, the previous and next pointers are examined to see - ; if we can defragment the heap. If the block to be breed is just next to the + ; 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 @@ -171,7 +172,42 @@ _addWibble__leave: ; HL = BLOCK Start & DE = Length. ; An init directive is useful for initialization routines. ; They will be added automatically if needed. -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" + ; Simple error control routines +; vim:ts=4:et: + push namespace core + 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 + pop namespace +#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -278,202 +314,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/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 - ; --------------------------------------------------------------------- - push namespace core -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 - pop namespace -#line 88 "arch/zx48k/ltee1.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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 MIT license - ; you can use it for any purpose (even for commercial - ; closed source programs). - ; - ; Please read the MIT license 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 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" - ; Simple error control routines -; vim:ts=4:et: - push namespace core - 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 - pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -504,9 +345,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -608,6 +449,165 @@ __LOADSTR: ; __FASTCALL__ entry pop hl ; Recovers destiny in hl as result ret pop namespace +#line 88 "arch/zx48k/ltee1.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; --------------------------------------------------------------------- + push namespace core +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 + pop namespace #line 89 "arch/zx48k/ltee1.bas" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/pstorestr.asm" ; vim:ts=4:et:sw=4 @@ -627,7 +627,7 @@ __LOADSTR: ; __FASTCALL__ entry ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/strcpy.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/realloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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/arch/zx48k/ltee3.asm b/tests/functional/arch/zx48k/ltee3.asm index cc9993eeb..787e1e196 100644 --- a/tests/functional/arch/zx48k/ltee3.asm +++ b/tests/functional/arch/zx48k/ltee3.asm @@ -71,17 +71,18 @@ _test__leave: DEFB 6Eh DEFB 67h ;; --- end of user code --- -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; This ASM library is licensed under the MIT license ; you can use it for any purpose (even for commercial ; closed source programs). ; - ; Please read the BSD license on the internet + ; Please read the MIT license on the internet ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. ; Each free block contains this info: @@ -122,7 +123,7 @@ _test__leave: ; | (0 if Size = 4)| ; +----------------+ ; When a block is FREED, the previous and next pointers are examined to see - ; if we can defragment the heap. If the block to be breed is just next to the + ; 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 @@ -131,7 +132,42 @@ _test__leave: ; HL = BLOCK Start & DE = Length. ; An init directive is useful for initialization routines. ; They will be added automatically if needed. -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" + ; Simple error control routines +; vim:ts=4:et: + push namespace core + 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 + pop namespace +#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -238,202 +274,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/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 - ; --------------------------------------------------------------------- - push namespace core -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 - pop namespace -#line 50 "arch/zx48k/ltee3.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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 MIT license - ; you can use it for any purpose (even for commercial - ; closed source programs). - ; - ; Please read the MIT license 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 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" - ; Simple error control routines -; vim:ts=4:et: - push namespace core - 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 - pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -464,9 +305,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -568,5 +409,164 @@ __LOADSTR: ; __FASTCALL__ entry pop hl ; Recovers destiny in hl as result ret pop namespace +#line 50 "arch/zx48k/ltee3.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; --------------------------------------------------------------------- + push namespace core +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 + pop namespace #line 51 "arch/zx48k/ltee3.bas" END diff --git a/tests/functional/arch/zx48k/opt1_len.asm b/tests/functional/arch/zx48k/opt1_len.asm index 8f15fcdeb..a6a140413 100644 --- a/tests/functional/arch/zx48k/opt1_len.asm +++ b/tests/functional/arch/zx48k/opt1_len.asm @@ -47,17 +47,22 @@ _c: ei ret ;; --- end of user code --- -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/io/keyboard/inkey.asm" + ; INKEY Function + ; Returns a string allocated in dynamic memory + ; containing the string. + ; An empty string otherwise. +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; This ASM library is licensed under the MIT license ; you can use it for any purpose (even for commercial ; closed source programs). ; - ; Please read the BSD license on the internet + ; Please read the MIT license on the internet ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. ; Each free block contains this info: @@ -98,7 +103,7 @@ _c: ; | (0 if Size = 4)| ; +----------------+ ; When a block is FREED, the previous and next pointers are examined to see - ; if we can defragment the heap. If the block to be breed is just next to the + ; 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 @@ -107,7 +112,42 @@ _c: ; HL = BLOCK Start & DE = Length. ; An init directive is useful for initialization routines. ; They will be added automatically if needed. -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" + ; Simple error control routines +; vim:ts=4:et: + push namespace core + 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 + pop namespace +#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -214,206 +254,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/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 - ; --------------------------------------------------------------------- - push namespace core -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 - pop namespace -#line 24 "arch/zx48k/opt1_len.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/io/keyboard/inkey.asm" - ; INKEY Function - ; Returns a string allocated in dynamic memory - ; containing the string. - ; An empty string otherwise. -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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 MIT license - ; you can use it for any purpose (even for commercial - ; closed source programs). - ; - ; Please read the MIT license 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 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" - ; Simple error control routines -; vim:ts=4:et: - push namespace core - 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 - pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -444,9 +285,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -556,6 +397,165 @@ __EMPTY_INKEY: KEY_CODE EQU 0333h ENDP pop namespace +#line 24 "arch/zx48k/opt1_len.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; --------------------------------------------------------------------- + push namespace core +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 + pop namespace #line 25 "arch/zx48k/opt1_len.bas" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/strlen.asm" ; Returns len if a string diff --git a/tests/functional/arch/zx48k/opt2_pstr.asm b/tests/functional/arch/zx48k/opt2_pstr.asm index 3d6bd5873..e21009402 100644 --- a/tests/functional/arch/zx48k/opt2_pstr.asm +++ b/tests/functional/arch/zx48k/opt2_pstr.asm @@ -68,17 +68,18 @@ _PRINT642__leave: DEFB 61h DEFB 32h ;; --- end of user code --- -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; This ASM library is licensed under the MIT license ; you can use it for any purpose (even for commercial ; closed source programs). ; - ; Please read the BSD license on the internet + ; Please read the MIT license on the internet ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. ; Each free block contains this info: @@ -119,7 +120,7 @@ _PRINT642__leave: ; | (0 if Size = 4)| ; +----------------+ ; When a block is FREED, the previous and next pointers are examined to see - ; if we can defragment the heap. If the block to be breed is just next to the + ; 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 @@ -128,7 +129,42 @@ _PRINT642__leave: ; HL = BLOCK Start & DE = Length. ; An init directive is useful for initialization routines. ; They will be added automatically if needed. -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" + ; Simple error control routines +; vim:ts=4:et: + push namespace core + 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 + pop namespace +#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -235,202 +271,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/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 - ; --------------------------------------------------------------------- - push namespace core -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 - pop namespace -#line 47 "arch/zx48k/opt2_pstr.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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 MIT license - ; you can use it for any purpose (even for commercial - ; closed source programs). - ; - ; Please read the MIT license 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 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" - ; Simple error control routines -; vim:ts=4:et: - push namespace core - 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 - pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -461,9 +302,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -565,5 +406,164 @@ __LOADSTR: ; __FASTCALL__ entry pop hl ; Recovers destiny in hl as result ret pop namespace +#line 47 "arch/zx48k/opt2_pstr.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; --------------------------------------------------------------------- + push namespace core +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 + pop namespace #line 48 "arch/zx48k/opt2_pstr.bas" END diff --git a/tests/functional/arch/zx48k/optional_param4.asm b/tests/functional/arch/zx48k/optional_param4.asm index 6fc8254ef..9a1f2e7e0 100644 --- a/tests/functional/arch/zx48k/optional_param4.asm +++ b/tests/functional/arch/zx48k/optional_param4.asm @@ -71,17 +71,18 @@ _test__leave: DEFW 0001h DEFB 41h ;; --- end of user code --- -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; This ASM library is licensed under the MIT license ; you can use it for any purpose (even for commercial ; closed source programs). ; - ; Please read the BSD license on the internet + ; Please read the MIT license on the internet ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. ; Each free block contains this info: @@ -122,7 +123,7 @@ _test__leave: ; | (0 if Size = 4)| ; +----------------+ ; When a block is FREED, the previous and next pointers are examined to see - ; if we can defragment the heap. If the block to be breed is just next to the + ; 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 @@ -131,7 +132,42 @@ _test__leave: ; HL = BLOCK Start & DE = Length. ; An init directive is useful for initialization routines. ; They will be added automatically if needed. -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" + ; Simple error control routines +; vim:ts=4:et: + push namespace core + 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 + pop namespace +#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -238,202 +274,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/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 - ; --------------------------------------------------------------------- - push namespace core -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 - pop namespace -#line 50 "arch/zx48k/optional_param4.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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 MIT license - ; you can use it for any purpose (even for commercial - ; closed source programs). - ; - ; Please read the MIT license 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 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" - ; Simple error control routines -; vim:ts=4:et: - push namespace core - 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 - pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -464,9 +305,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -568,5 +409,164 @@ __LOADSTR: ; __FASTCALL__ entry pop hl ; Recovers destiny in hl as result ret pop namespace +#line 50 "arch/zx48k/optional_param4.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; --------------------------------------------------------------------- + push namespace core +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 + pop namespace #line 51 "arch/zx48k/optional_param4.bas" END diff --git a/tests/functional/arch/zx48k/param0.asm b/tests/functional/arch/zx48k/param0.asm index 491ebe69f..511483d4a 100644 --- a/tests/functional/arch/zx48k/param0.asm +++ b/tests/functional/arch/zx48k/param0.asm @@ -74,17 +74,18 @@ _test__leave: DEFW 0001h DEFB 41h ;; --- end of user code --- -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; This ASM library is licensed under the MIT license ; you can use it for any purpose (even for commercial ; closed source programs). ; - ; Please read the BSD license on the internet + ; Please read the MIT license on the internet ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. ; Each free block contains this info: @@ -125,7 +126,7 @@ _test__leave: ; | (0 if Size = 4)| ; +----------------+ ; When a block is FREED, the previous and next pointers are examined to see - ; if we can defragment the heap. If the block to be breed is just next to the + ; 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 @@ -134,7 +135,42 @@ _test__leave: ; HL = BLOCK Start & DE = Length. ; An init directive is useful for initialization routines. ; They will be added automatically if needed. -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" + ; Simple error control routines +; vim:ts=4:et: + push namespace core + 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 + pop namespace +#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -241,202 +277,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/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 - ; --------------------------------------------------------------------- - push namespace core -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 - pop namespace -#line 53 "arch/zx48k/param0.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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 MIT license - ; you can use it for any purpose (even for commercial - ; closed source programs). - ; - ; Please read the MIT license 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 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" - ; Simple error control routines -; vim:ts=4:et: - push namespace core - 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 - pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -467,9 +308,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -571,6 +412,165 @@ __LOADSTR: ; __FASTCALL__ entry pop hl ; Recovers destiny in hl as result ret pop namespace +#line 53 "arch/zx48k/param0.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; --------------------------------------------------------------------- + push namespace core +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 + pop namespace #line 54 "arch/zx48k/param0.bas" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/strcat.asm" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/strlen.asm" diff --git a/tests/functional/arch/zx48k/param2.asm b/tests/functional/arch/zx48k/param2.asm index d1284199d..8f78feb31 100644 --- a/tests/functional/arch/zx48k/param2.asm +++ b/tests/functional/arch/zx48k/param2.asm @@ -74,17 +74,18 @@ _test__leave: DEFW 0001h DEFB 41h ;; --- end of user code --- -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; This ASM library is licensed under the MIT license ; you can use it for any purpose (even for commercial ; closed source programs). ; - ; Please read the BSD license on the internet + ; Please read the MIT license on the internet ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. ; Each free block contains this info: @@ -125,7 +126,7 @@ _test__leave: ; | (0 if Size = 4)| ; +----------------+ ; When a block is FREED, the previous and next pointers are examined to see - ; if we can defragment the heap. If the block to be breed is just next to the + ; 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 @@ -134,7 +135,42 @@ _test__leave: ; HL = BLOCK Start & DE = Length. ; An init directive is useful for initialization routines. ; They will be added automatically if needed. -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" + ; Simple error control routines +; vim:ts=4:et: + push namespace core + 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 + pop namespace +#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -241,202 +277,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/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 - ; --------------------------------------------------------------------- - push namespace core -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 - pop namespace -#line 53 "arch/zx48k/param2.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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 MIT license - ; you can use it for any purpose (even for commercial - ; closed source programs). - ; - ; Please read the MIT license 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 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" - ; Simple error control routines -; vim:ts=4:et: - push namespace core - 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 - pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -467,9 +308,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -571,6 +412,165 @@ __LOADSTR: ; __FASTCALL__ entry pop hl ; Recovers destiny in hl as result ret pop namespace +#line 53 "arch/zx48k/param2.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; --------------------------------------------------------------------- + push namespace core +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 + pop namespace #line 54 "arch/zx48k/param2.bas" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/strcat.asm" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/strlen.asm" diff --git a/tests/functional/arch/zx48k/paramstr3.asm b/tests/functional/arch/zx48k/paramstr3.asm index 971aa246c..029e52675 100644 --- a/tests/functional/arch/zx48k/paramstr3.asm +++ b/tests/functional/arch/zx48k/paramstr3.asm @@ -63,17 +63,18 @@ _p__leave: exx ret ;; --- end of user code --- -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; This ASM library is licensed under the MIT license ; you can use it for any purpose (even for commercial ; closed source programs). ; - ; Please read the BSD license on the internet + ; Please read the MIT license on the internet ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. ; Each free block contains this info: @@ -114,7 +115,7 @@ _p__leave: ; | (0 if Size = 4)| ; +----------------+ ; When a block is FREED, the previous and next pointers are examined to see - ; if we can defragment the heap. If the block to be breed is just next to the + ; 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 @@ -123,7 +124,42 @@ _p__leave: ; HL = BLOCK Start & DE = Length. ; An init directive is useful for initialization routines. ; They will be added automatically if needed. -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" + ; Simple error control routines +; vim:ts=4:et: + push namespace core + 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 + pop namespace +#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -230,202 +266,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/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 - ; --------------------------------------------------------------------- - push namespace core -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 - pop namespace -#line 40 "arch/zx48k/paramstr3.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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 MIT license - ; you can use it for any purpose (even for commercial - ; closed source programs). - ; - ; Please read the MIT license 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 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" - ; Simple error control routines -; vim:ts=4:et: - push namespace core - 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 - pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -456,9 +297,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -560,5 +401,164 @@ __LOADSTR: ; __FASTCALL__ entry pop hl ; Recovers destiny in hl as result ret pop namespace +#line 40 "arch/zx48k/paramstr3.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; --------------------------------------------------------------------- + push namespace core +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 + pop namespace #line 41 "arch/zx48k/paramstr3.bas" END diff --git a/tests/functional/arch/zx48k/paramstr4.asm b/tests/functional/arch/zx48k/paramstr4.asm index b8647326b..f6380c218 100644 --- a/tests/functional/arch/zx48k/paramstr4.asm +++ b/tests/functional/arch/zx48k/paramstr4.asm @@ -87,17 +87,18 @@ _r__leave: exx ret ;; --- end of user code --- -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; This ASM library is licensed under the MIT license ; you can use it for any purpose (even for commercial ; closed source programs). ; - ; Please read the BSD license on the internet + ; Please read the MIT license on the internet ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. ; Each free block contains this info: @@ -138,7 +139,7 @@ _r__leave: ; | (0 if Size = 4)| ; +----------------+ ; When a block is FREED, the previous and next pointers are examined to see - ; if we can defragment the heap. If the block to be breed is just next to the + ; 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 @@ -147,7 +148,42 @@ _r__leave: ; HL = BLOCK Start & DE = Length. ; An init directive is useful for initialization routines. ; They will be added automatically if needed. -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" + ; Simple error control routines +; vim:ts=4:et: + push namespace core + 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 + pop namespace +#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -254,202 +290,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/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 - ; --------------------------------------------------------------------- - push namespace core -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 - pop namespace -#line 64 "arch/zx48k/paramstr4.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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 MIT license - ; you can use it for any purpose (even for commercial - ; closed source programs). - ; - ; Please read the MIT license 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 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" - ; Simple error control routines -; vim:ts=4:et: - push namespace core - 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 - pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -480,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -584,5 +425,164 @@ __LOADSTR: ; __FASTCALL__ entry pop hl ; Recovers destiny in hl as result ret pop namespace +#line 64 "arch/zx48k/paramstr4.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; --------------------------------------------------------------------- + push namespace core +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 + pop namespace #line 65 "arch/zx48k/paramstr4.bas" END diff --git a/tests/functional/arch/zx48k/paramstr5.asm b/tests/functional/arch/zx48k/paramstr5.asm index 691a70955..39df4ea8f 100644 --- a/tests/functional/arch/zx48k/paramstr5.asm +++ b/tests/functional/arch/zx48k/paramstr5.asm @@ -87,17 +87,18 @@ _p_r__leave: exx ret ;; --- end of user code --- -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; This ASM library is licensed under the MIT license ; you can use it for any purpose (even for commercial ; closed source programs). ; - ; Please read the BSD license on the internet + ; Please read the MIT license on the internet ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. ; Each free block contains this info: @@ -138,7 +139,7 @@ _p_r__leave: ; | (0 if Size = 4)| ; +----------------+ ; When a block is FREED, the previous and next pointers are examined to see - ; if we can defragment the heap. If the block to be breed is just next to the + ; 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 @@ -147,7 +148,42 @@ _p_r__leave: ; HL = BLOCK Start & DE = Length. ; An init directive is useful for initialization routines. ; They will be added automatically if needed. -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" + ; Simple error control routines +; vim:ts=4:et: + push namespace core + 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 + pop namespace +#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -254,202 +290,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/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 - ; --------------------------------------------------------------------- - push namespace core -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 - pop namespace -#line 64 "arch/zx48k/paramstr5.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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 MIT license - ; you can use it for any purpose (even for commercial - ; closed source programs). - ; - ; Please read the MIT license 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 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" - ; Simple error control routines -; vim:ts=4:et: - push namespace core - 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 - pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -480,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -584,5 +425,164 @@ __LOADSTR: ; __FASTCALL__ entry pop hl ; Recovers destiny in hl as result ret pop namespace +#line 64 "arch/zx48k/paramstr5.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; --------------------------------------------------------------------- + push namespace core +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 + pop namespace #line 65 "arch/zx48k/paramstr5.bas" END diff --git a/tests/functional/arch/zx48k/slice2.asm b/tests/functional/arch/zx48k/slice2.asm index a87da27c9..ee6a8945b 100644 --- a/tests/functional/arch/zx48k/slice2.asm +++ b/tests/functional/arch/zx48k/slice2.asm @@ -220,17 +220,18 @@ __STOP: ret pop namespace #line 107 "arch/zx48k/slice2.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; This ASM library is licensed under the MIT license ; you can use it for any purpose (even for commercial ; closed source programs). ; - ; Please read the BSD license on the internet + ; Please read the MIT license on the internet ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. ; Each free block contains this info: @@ -271,7 +272,7 @@ __STOP: ; | (0 if Size = 4)| ; +----------------+ ; When a block is FREED, the previous and next pointers are examined to see - ; if we can defragment the heap. If the block to be breed is just next to the + ; 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 @@ -280,7 +281,7 @@ __STOP: ; HL = BLOCK Start & DE = Length. ; An init directive is useful for initialization routines. ; They will be added automatically if needed. -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -387,167 +388,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/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 - ; --------------------------------------------------------------------- - push namespace core -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 - pop namespace -#line 108 "arch/zx48k/slice2.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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 MIT license - ; you can use it for any purpose (even for commercial - ; closed source programs). - ; - ; Please read the MIT license 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 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -578,9 +419,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -682,6 +523,165 @@ __LOADSTR: ; __FASTCALL__ entry pop hl ; Recovers destiny in hl as result ret pop namespace +#line 108 "arch/zx48k/slice2.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; --------------------------------------------------------------------- + push namespace core +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 + pop namespace #line 109 "arch/zx48k/slice2.bas" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/pstorestr2.asm" ; vim:ts=4:et:sw=4 diff --git a/tests/functional/arch/zx48k/stdlib_screen.asm b/tests/functional/arch/zx48k/stdlib_screen.asm index 6be051ab3..cb9b8528d 100644 --- a/tests/functional/arch/zx48k/stdlib_screen.asm +++ b/tests/functional/arch/zx48k/stdlib_screen.asm @@ -104,7 +104,8 @@ _screen__leave: exx ret ;; --- end of user code --- -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -198,8 +199,8 @@ __STOP: ld (ERR_NR), a ret pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" +#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -306,7 +307,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -337,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -404,8 +405,45 @@ __MEM_SUBTRACT: ret ENDP pop namespace +#line 2 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" + ; Loads a string (ptr) from HL + ; and duplicates it on dynamic memory again + ; Finally, it returns result pointer in HL + push namespace core +__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 + pop namespace #line 113 "/zxbasic/src/lib/arch/zx48k/stdlib/screen.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/free.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -563,44 +601,6 @@ __MEM_BLOCK_JOIN: ; Joins current block (pointed by HL) with next one (pointed ret ENDP pop namespace -#line 114 "/zxbasic/src/lib/arch/zx48k/stdlib/screen.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" - ; Loads a string (ptr) from HL - ; and duplicates it on dynamic memory again - ; Finally, it returns result pointer in HL - push namespace core -__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 - pop namespace #line 115 "/zxbasic/src/lib/arch/zx48k/stdlib/screen.bas" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/stackf.asm" ; ------------------------------------------------------------- diff --git a/tests/functional/arch/zx48k/storestr2.asm b/tests/functional/arch/zx48k/storestr2.asm index 17bbcdb75..118833cb9 100644 --- a/tests/functional/arch/zx48k/storestr2.asm +++ b/tests/functional/arch/zx48k/storestr2.asm @@ -86,17 +86,18 @@ _test__leave: DEFB 6Ch DEFB 6Fh ;; --- end of user code --- -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; This ASM library is licensed under the MIT license ; you can use it for any purpose (even for commercial ; closed source programs). ; - ; Please read the BSD license on the internet + ; Please read the MIT license on the internet ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. ; Each free block contains this info: @@ -137,7 +138,7 @@ _test__leave: ; | (0 if Size = 4)| ; +----------------+ ; When a block is FREED, the previous and next pointers are examined to see - ; if we can defragment the heap. If the block to be breed is just next to the + ; 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 @@ -146,7 +147,42 @@ _test__leave: ; HL = BLOCK Start & DE = Length. ; An init directive is useful for initialization routines. ; They will be added automatically if needed. -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" + ; Simple error control routines +; vim:ts=4:et: + push namespace core + 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 + pop namespace +#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -253,202 +289,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/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 - ; --------------------------------------------------------------------- - push namespace core -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 - pop namespace -#line 63 "arch/zx48k/storestr2.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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 MIT license - ; you can use it for any purpose (even for commercial - ; closed source programs). - ; - ; Please read the MIT license 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 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" - ; Simple error control routines -; vim:ts=4:et: - push namespace core - 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 - pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -479,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -583,7 +424,166 @@ __LOADSTR: ; __FASTCALL__ entry pop hl ; Recovers destiny in hl as result ret pop namespace -#line 64 "arch/zx48k/storestr2.bas" +#line 63 "./arch/zx48k/storestr2.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; --------------------------------------------------------------------- + push namespace core +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 + pop namespace +#line 64 "./arch/zx48k/storestr2.bas" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/pstorestr.asm" ; vim:ts=4:et:sw=4 ; @@ -602,7 +602,7 @@ __LOADSTR: ; __FASTCALL__ entry ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/strcpy.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/realloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/realloc.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -846,5 +846,5 @@ __PSTORE_STR: add hl, bc jp __STORE_STR pop namespace -#line 65 "arch/zx48k/storestr2.bas" +#line 65 "./arch/zx48k/storestr2.bas" END diff --git a/tests/functional/arch/zx48k/str_slash.asm b/tests/functional/arch/zx48k/str_slash.asm index 1c79897ff..78dbed40f 100644 --- a/tests/functional/arch/zx48k/str_slash.asm +++ b/tests/functional/arch/zx48k/str_slash.asm @@ -79,17 +79,18 @@ _GetFileSize__leave: DEFB 6Eh DEFB 65h ;; --- end of user code --- -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; This ASM library is licensed under the MIT license ; you can use it for any purpose (even for commercial ; closed source programs). ; - ; Please read the BSD license on the internet + ; Please read the MIT license on the internet ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. ; Each free block contains this info: @@ -130,7 +131,7 @@ _GetFileSize__leave: ; | (0 if Size = 4)| ; +----------------+ ; When a block is FREED, the previous and next pointers are examined to see - ; if we can defragment the heap. If the block to be breed is just next to the + ; 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 @@ -139,7 +140,42 @@ _GetFileSize__leave: ; HL = BLOCK Start & DE = Length. ; An init directive is useful for initialization routines. ; They will be added automatically if needed. -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" + ; Simple error control routines +; vim:ts=4:et: + push namespace core + 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 + pop namespace +#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -246,202 +282,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/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 - ; --------------------------------------------------------------------- - push namespace core -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 - pop namespace -#line 58 "arch/zx48k/str_slash.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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 MIT license - ; you can use it for any purpose (even for commercial - ; closed source programs). - ; - ; Please read the MIT license 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 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" - ; Simple error control routines -; vim:ts=4:et: - push namespace core - 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 - pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -472,9 +313,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -576,5 +417,164 @@ __LOADSTR: ; __FASTCALL__ entry pop hl ; Recovers destiny in hl as result ret pop namespace -#line 59 "arch/zx48k/str_slash.bas" +#line 58 "./arch/zx48k/str_slash.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; --------------------------------------------------------------------- + push namespace core +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 + pop namespace +#line 59 "./arch/zx48k/str_slash.bas" END diff --git a/tests/functional/arch/zx48k/stringfunc.asm b/tests/functional/arch/zx48k/stringfunc.asm index b820e174d..d3aa57efa 100644 --- a/tests/functional/arch/zx48k/stringfunc.asm +++ b/tests/functional/arch/zx48k/stringfunc.asm @@ -57,17 +57,18 @@ _testStr__leave: DEFB 6Ch DEFB 6Fh ;; --- end of user code --- -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; This ASM library is licensed under the MIT license ; you can use it for any purpose (even for commercial ; closed source programs). ; - ; Please read the BSD license on the internet + ; Please read the MIT license on the internet ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. ; Each free block contains this info: @@ -108,7 +109,7 @@ _testStr__leave: ; | (0 if Size = 4)| ; +----------------+ ; When a block is FREED, the previous and next pointers are examined to see - ; if we can defragment the heap. If the block to be breed is just next to the + ; 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 @@ -117,7 +118,42 @@ _testStr__leave: ; HL = BLOCK Start & DE = Length. ; An init directive is useful for initialization routines. ; They will be added automatically if needed. -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" + ; Simple error control routines +; vim:ts=4:et: + push namespace core + 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 + pop namespace +#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -224,202 +260,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/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 - ; --------------------------------------------------------------------- - push namespace core -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 - pop namespace -#line 36 "arch/zx48k/stringfunc.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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 MIT license - ; you can use it for any purpose (even for commercial - ; closed source programs). - ; - ; Please read the MIT license 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 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" - ; Simple error control routines -; vim:ts=4:et: - push namespace core - 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 - pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -450,9 +291,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -554,5 +395,164 @@ __LOADSTR: ; __FASTCALL__ entry pop hl ; Recovers destiny in hl as result ret pop namespace -#line 37 "arch/zx48k/stringfunc.bas" +#line 36 "./arch/zx48k/stringfunc.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; --------------------------------------------------------------------- + push namespace core +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 + pop namespace +#line 37 "./arch/zx48k/stringfunc.bas" END diff --git a/tests/functional/arch/zx48k/stringparam.asm b/tests/functional/arch/zx48k/stringparam.asm index 4bb9af591..1437858af 100644 --- a/tests/functional/arch/zx48k/stringparam.asm +++ b/tests/functional/arch/zx48k/stringparam.asm @@ -988,18 +988,19 @@ __REFRESH_TMP: ret ENDP pop namespace -#line 53 "arch/zx48k/stringparam.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 53 "./arch/zx48k/stringparam.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; This ASM library is licensed under the MIT license ; you can use it for any purpose (even for commercial ; closed source programs). ; - ; Please read the BSD license on the internet + ; Please read the MIT license on the internet ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. ; Each free block contains this info: @@ -1040,7 +1041,7 @@ __REFRESH_TMP: ; | (0 if Size = 4)| ; +----------------+ ; When a block is FREED, the previous and next pointers are examined to see - ; if we can defragment the heap. If the block to be breed is just next to the + ; 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 @@ -1049,7 +1050,7 @@ __REFRESH_TMP: ; HL = BLOCK Start & DE = Length. ; An init directive is useful for initialization routines. ; They will be added automatically if needed. -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1156,167 +1157,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/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 - ; --------------------------------------------------------------------- - push namespace core -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 - pop namespace -#line 54 "arch/zx48k/stringparam.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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 MIT license - ; you can use it for any purpose (even for commercial - ; closed source programs). - ; - ; Please read the MIT license 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 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -1347,9 +1188,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -1451,7 +1292,166 @@ __LOADSTR: ; __FASTCALL__ entry pop hl ; Recovers destiny in hl as result ret pop namespace -#line 55 "arch/zx48k/stringparam.bas" +#line 54 "./arch/zx48k/stringparam.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; --------------------------------------------------------------------- + push namespace core +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 + pop namespace +#line 55 "./arch/zx48k/stringparam.bas" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/printstr.asm" ; PRINT command routine ; Prints string pointed by HL @@ -1495,5 +1495,5 @@ __PRINT_STR: jp __PRINT_STR_LOOP ENDP pop namespace -#line 57 "arch/zx48k/stringparam.bas" +#line 57 "./arch/zx48k/stringparam.bas" END diff --git a/tests/functional/arch/zx48k/strparam0.asm b/tests/functional/arch/zx48k/strparam0.asm index cd4f21d90..3a8e5a6d0 100644 --- a/tests/functional/arch/zx48k/strparam0.asm +++ b/tests/functional/arch/zx48k/strparam0.asm @@ -1018,18 +1018,19 @@ __REFRESH_TMP: ret ENDP pop namespace -#line 83 "arch/zx48k/strparam0.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 83 "./arch/zx48k/strparam0.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; This ASM library is licensed under the MIT license ; you can use it for any purpose (even for commercial ; closed source programs). ; - ; Please read the BSD license on the internet + ; Please read the MIT license on the internet ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. ; Each free block contains this info: @@ -1070,7 +1071,7 @@ __REFRESH_TMP: ; | (0 if Size = 4)| ; +----------------+ ; When a block is FREED, the previous and next pointers are examined to see - ; if we can defragment the heap. If the block to be breed is just next to the + ; 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 @@ -1079,7 +1080,7 @@ __REFRESH_TMP: ; HL = BLOCK Start & DE = Length. ; An init directive is useful for initialization routines. ; They will be added automatically if needed. -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1186,167 +1187,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/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 - ; --------------------------------------------------------------------- - push namespace core -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 - pop namespace -#line 84 "arch/zx48k/strparam0.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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 MIT license - ; you can use it for any purpose (even for commercial - ; closed source programs). - ; - ; Please read the MIT license 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 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -1377,9 +1218,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -1481,7 +1322,166 @@ __LOADSTR: ; __FASTCALL__ entry pop hl ; Recovers destiny in hl as result ret pop namespace -#line 85 "arch/zx48k/strparam0.bas" +#line 84 "./arch/zx48k/strparam0.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; --------------------------------------------------------------------- + push namespace core +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 + pop namespace +#line 85 "./arch/zx48k/strparam0.bas" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/printstr.asm" ; PRINT command routine ; Prints string pointed by HL @@ -1525,5 +1525,5 @@ __PRINT_STR: jp __PRINT_STR_LOOP ENDP pop namespace -#line 87 "arch/zx48k/strparam0.bas" +#line 87 "./arch/zx48k/strparam0.bas" END diff --git a/tests/functional/arch/zx48k/strparam3.asm b/tests/functional/arch/zx48k/strparam3.asm index f95282d7e..df2738445 100644 --- a/tests/functional/arch/zx48k/strparam3.asm +++ b/tests/functional/arch/zx48k/strparam3.asm @@ -1012,18 +1012,19 @@ __REFRESH_TMP: ret ENDP pop namespace -#line 77 "arch/zx48k/strparam3.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 77 "./arch/zx48k/strparam3.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; This ASM library is licensed under the MIT license ; you can use it for any purpose (even for commercial ; closed source programs). ; - ; Please read the BSD license on the internet + ; Please read the MIT license on the internet ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. ; Each free block contains this info: @@ -1064,7 +1065,7 @@ __REFRESH_TMP: ; | (0 if Size = 4)| ; +----------------+ ; When a block is FREED, the previous and next pointers are examined to see - ; if we can defragment the heap. If the block to be breed is just next to the + ; 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 @@ -1073,7 +1074,7 @@ __REFRESH_TMP: ; HL = BLOCK Start & DE = Length. ; An init directive is useful for initialization routines. ; They will be added automatically if needed. -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -1180,167 +1181,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/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 - ; --------------------------------------------------------------------- - push namespace core -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 - pop namespace -#line 78 "arch/zx48k/strparam3.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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 MIT license - ; you can use it for any purpose (even for commercial - ; closed source programs). - ; - ; Please read the MIT license 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 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -1371,9 +1212,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -1475,7 +1316,166 @@ __LOADSTR: ; __FASTCALL__ entry pop hl ; Recovers destiny in hl as result ret pop namespace -#line 79 "arch/zx48k/strparam3.bas" +#line 78 "./arch/zx48k/strparam3.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; --------------------------------------------------------------------- + push namespace core +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 + pop namespace +#line 79 "./arch/zx48k/strparam3.bas" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/printstr.asm" ; PRINT command routine ; Prints string pointed by HL @@ -1519,5 +1519,5 @@ __PRINT_STR: jp __PRINT_STR_LOOP ENDP pop namespace -#line 81 "arch/zx48k/strparam3.bas" +#line 81 "./arch/zx48k/strparam3.bas" END diff --git a/tests/functional/arch/zx48k/valcrash1.asm b/tests/functional/arch/zx48k/valcrash1.asm index 2a25e22e3..ec47d8e52 100644 --- a/tests/functional/arch/zx48k/valcrash1.asm +++ b/tests/functional/arch/zx48k/valcrash1.asm @@ -80,17 +80,18 @@ _test__leave: DEFW 0001h DEFB 35h ;; --- end of user code --- -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/free.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; This ASM library is licensed under the MIT license ; you can use it for any purpose (even for commercial ; closed source programs). ; - ; Please read the BSD license on the internet + ; Please read the MIT license on the internet ; ----- IMPLEMENTATION NOTES ------ ; The heap is implemented as a linked list of free blocks. ; Each free block contains this info: @@ -131,7 +132,7 @@ _test__leave: ; | (0 if Size = 4)| ; +----------------+ ; When a block is FREED, the previous and next pointers are examined to see - ; if we can defragment the heap. If the block to be breed is just next to the + ; 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 @@ -140,7 +141,42 @@ _test__leave: ; HL = BLOCK Start & DE = Length. ; An init directive is useful for initialization routines. ; They will be added automatically if needed. -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/heapinit.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" + ; Simple error control routines +; vim:ts=4:et: + push namespace core + 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 + pop namespace +#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/heapinit.asm" ; vim: ts=4:et:sw=4: ; Copyleft (K) by Jose M. Rodriguez de la Rosa ; (a.k.a. Boriel) @@ -247,202 +283,7 @@ __MEM_INIT2: ret ENDP pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/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 - ; --------------------------------------------------------------------- - push namespace core -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 - pop namespace -#line 57 "arch/zx48k/valcrash1.bas" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/loadstr.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/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 MIT license - ; you can use it for any purpose (even for commercial - ; closed source programs). - ; - ; Please read the MIT license 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 "/zxbasic/src/lib/arch/zx48k/runtime/error.asm" - ; Simple error control routines -; vim:ts=4:et: - push namespace core - 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 - pop namespace -#line 69 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 70 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; --------------------------------------------------------------------- ; MEM_ALLOC ; Allocates a block of memory in the heap. @@ -473,9 +314,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 113 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 113 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ret z ; NULL -#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/alloc.asm" +#line 115 "/zxbasic/src/lib/arch/zx48k/runtime/mem/alloc.asm" ; HL = Pointer to Free block ld e, (hl) inc hl @@ -577,6 +418,165 @@ __LOADSTR: ; __FASTCALL__ entry pop hl ; Recovers destiny in hl as result ret pop namespace +#line 57 "arch/zx48k/valcrash1.bas" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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 + ; --------------------------------------------------------------------- + push namespace core +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 + pop namespace #line 58 "arch/zx48k/valcrash1.bas" #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/pstoref.asm" ; Stores FP number in A ED CB at location HL+IX @@ -636,7 +636,7 @@ __PSTOREF: ; This function will resize (REALLOC) the space pointed by HL ; before copying the content of b$ into a$ #line 1 "/zxbasic/src/lib/arch/zx48k/runtime/strcpy.asm" -#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/realloc.asm" +#line 1 "/zxbasic/src/lib/arch/zx48k/runtime/mem/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/zxbpp/prepro71.out b/tests/functional/zxbpp/prepro71.out index 0107c790c..9d1274edd 100644 --- a/tests/functional/zxbpp/prepro71.out +++ b/tests/functional/zxbpp/prepro71.out @@ -232,10 +232,10 @@ end function #pragma pop(case_insensitive) -#require "alloc.asm" -#require "free.asm" -#require "realloc.asm" -#require "calloc.asm" +#require "mem/alloc.asm" +#require "mem/free.asm" +#require "mem/realloc.asm" +#require "mem/calloc.asm" #line 239 "/zxbasic/src/lib/arch/zx48k/stdlib/alloc.bas" #line 2 "prepro71.bi" From 53cdd89a829f5df939a330c07054856cad8dab7d Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Tue, 26 Aug 2025 20:02:48 +0200 Subject: [PATCH 4/4] fix linting --- src/arch/z80/backend/common.py | 1 + src/arch/z80/optimizer/cpustate.py | 6 +++--- src/zxbasm/memory.py | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/arch/z80/backend/common.py b/src/arch/z80/backend/common.py index 363dfdc0a..b49f0e3f3 100644 --- a/src/arch/z80/backend/common.py +++ b/src/arch/z80/backend/common.py @@ -7,6 +7,7 @@ from src.api import global_, tmp_labels from src.api.config import OPTIONS, OptimizationStrategy from src.api.exception import TempAlreadyFreedError + from .runtime import LABEL_REQUIRED_MODULES, NAMESPACE, RUNTIME_LABELS from .runtime import Labels as RuntimeLabel diff --git a/src/arch/z80/optimizer/cpustate.py b/src/arch/z80/optimizer/cpustate.py index d30206a89..8e845a533 100644 --- a/src/arch/z80/optimizer/cpustate.py +++ b/src/arch/z80/optimizer/cpustate.py @@ -410,9 +410,9 @@ def set(self, r: str, val: int | str | None) -> None: if is_unknown8(val): val = f"{new_tmp_val()}{HL_SEP}{val}" - assert ( - is_num or is_unknown16(val) or is_label(val) - ), f"val '{val}' is neither a number, nor a label nor an unknown16" + assert is_num or is_unknown16(val) or is_label(val), ( + f"val '{val}' is neither a number, nor a label nor an unknown16" + ) self.regs[r] = val if is_16bit_composed_register(r): # sp register is not included. Special case diff --git a/src/zxbasm/memory.py b/src/zxbasm/memory.py index 1d83383c7..4a1e0732a 100644 --- a/src/zxbasm/memory.py +++ b/src/zxbasm/memory.py @@ -222,9 +222,9 @@ def declare_label( fname = gl.FILENAME if label.isdecimal(): # Temporary label? - assert ( - not self._tmp_labels_lines[fname] or self._tmp_labels_lines[fname][-1] <= lineno - ), "Temporary label out of order" + assert not self._tmp_labels_lines[fname] or self._tmp_labels_lines[fname][-1] <= lineno, ( + "Temporary label out of order" + ) if not self._tmp_labels_lines[fname] or self._tmp_labels_lines[fname][-1] != lineno: self._tmp_labels_lines[fname].append(lineno)