These macros are intended for use in Brass, and caters to FlashAPP developers, who may need to use routines that involve SMC
These macros allow an easy way to statically allocate memory to userMem and beyond and be able to use them just like any normal variable or routine that's been relocated to RAM without ever explicitly defining where each piece should go.
This is accomplished both at build-time and at run-time, where the information needed for relocation is built and at run-time. A routine is called to reserve memory at userMem via _InsertMem and copy relocated routines to the appropriate places.
Keep in mind, this is only useful if you need to put more than one different thing at userMem and do not want to have to do such things as calculate how large each scrap of memory you're reserving or where to .relocate / copy routines to RAM. I did that for CaDan and went on an ice cream binge when I needed to rearrange things. (Needless to say, that project never finished)
Anyhoo. The goods.
These macros needs to go at or near the top of the main project file, before you actually use them. I put them in with my variable declarations.
Code:
The following stuff goes at the bottom of the code, or where no more alloc/reloc will happen. There's some error checking and the macros are designed to throw an error if you try it, tho.
Code:
Usage
To reserve a chunk of memory. Known limitation: the size if calculated from labels, must not forward-reference.
Code:
To relocate a routine to memory:
Code:
And most importantly, to make sure the memory is actually allocated, you must call allocExtraRAM near the beginning of your program to format and copy the routines to RAM, and call deallocExtraRAM to clean up memory right before you exit.
My hope is that this is useful to someone. If not, blame geekboy. He convinced me to post this.
These macros allow an easy way to statically allocate memory to userMem and beyond and be able to use them just like any normal variable or routine that's been relocated to RAM without ever explicitly defining where each piece should go.
This is accomplished both at build-time and at run-time, where the information needed for relocation is built and at run-time. A routine is called to reserve memory at userMem via _InsertMem and copy relocated routines to the appropriate places.
Keep in mind, this is only useful if you need to put more than one different thing at userMem and do not want to have to do such things as calculate how large each scrap of memory you're reserving or where to .relocate / copy routines to RAM. I did that for CaDan and went on an ice cream binge when I needed to rearrange things. (Needless to say, that project never finished)
Anyhoo. The goods.
These macros needs to go at or near the top of the main project file, before you actually use them. I put them in with my variable declarations.
Code:
userMemPtr = userMem ;rolling pointer for compile-time mem alloc
allocRtnCount = 0 ;for keeping track of allocations for routines
allocRtnLoopSeal = 0 ;toggles to ensure reloc2 loops are not nested
.deflong allocMem(size,labelname)
.ifdef mem_utils_table
.fail "Cannot alloc after tbl define in mem_utils.z80!"
.endif
labelname = userMemPtr
tvar1 = userMemPtr + size
userMemPtr = tvar1
.enddeflong
.deflong reloc2()
.if allocRtnLoopSeal
.fail "Cannot nest reloc2() macro calls"
.endif
.ifdef mem_utils_table
.fail "Cannot reloc after tbl define in mem_utils.z80!"
.endif
tvarSt = $
allocRtnLoopSeal = 1
.relocate userMemPtr
.enddeflong
.deflong endreloc2()
.endrelocate
allocRtnLoopSeal = 0
size = $-tvarSt
oldUserMemPtr = userMemPtr
tvar1 = userMemPtr + size
userMemPtr = tvar1
tvar1 = allocRtnCount + 1
allocRtnCount = tvar1
allocMemPtr_{allocRtnCount} = tvarSt
allocMemSiz_{allocRtnCount} = size
allocMemVar_{allocRtnCount} = oldUserMemPtr
.enddeflong
The following stuff goes at the bottom of the code, or where no more alloc/reloc will happen. There's some error checking and the macros are designed to throw an error if you try it, tho.
Code:
.module memutils
#define mem_utils_table() 1
;In: None
;Out: carry set if alloc failed
;Dstr: All registers
allocExtraRAM:
.if userMemPtr==userMem
or a
ret
.else
;Because of inits, _memAllocated is supposed to be 0 before this starts
.var word,_memAllocated
;---------------------------------------------------------------------------
totalUserMemSize = userMemPtr-userMem
ld hl,0
ld (_memAllocated),hl
ld hl,totalUserMemSize
push hl
bcall(noname._EnoughMem)
pop hl
ret c
ld (_memAllocated),hl
ld de,userMem
.if totalUserMemSize==1
push hl
bcall(_InsertMem)
pop hl
ld (hl),0
.else
push hl
push de
bcall(noname._InsertMem)
pop hl
pop bc
ld (hl),0
ld e,L
ld d,H
inc de
dec bc
ldir
.endif
.endif
.if allocRtnCount == 0
or a
ret
.else
ld hl,memUtils_address_table
ld b,allocRtnCount
_allocMemLoop:
push bc
ld e,(hl)
inc hl
ld d,(hl)
inc hl
ld c,(hl)
inc hl
ld b,(hl)
inc hl
ld a,(hl)
inc hl
push hl
ld h,(hl)
ld L,a
ldir
pop hl
inc hl
pop bc
djnz _allocMemLoop
or a
ret
.endif
;no inputs. Destroys all registers (probably). Used for cleanup prior to app exit
deallocExtraRAM:
.if userMemPtr==userMem
ret
.else
ld de,(_memAllocated)
ld a,e
or d
ret z ;if no mem was allocated, do not attempt deallocation (else crash)
ld hl,userMem
bcall(noname._DelMem)
ret
.endif
;SRC HL allocMemPtr_{i} = replacementPtr
;SIZ BC allocMemSiz_{i} = size
;DEST DE allocMemVar_{i} = oldUserMemPtr
memUtils_address_table:
.if allocRtnCount
.for i,1,allocRtnCount
.dw allocMemVar_{i},allocMemSiz_{i},allocMemPtr_{i}
.loop
.endif
.echoln "Number of routine allocs: ",allocRtnCount
.endmodule
Usage
To reserve a chunk of memory. Known limitation: the size if calculated from labels, must not forward-reference.
Code:
;To reserve 2048 bytes starting at a new variable called "myVariable"
allocMem(2048,myVariable)
To relocate a routine to memory:
Code:
;An example routine that demonstrates that
;labels have changed and that the routine
;uses SMC since it was copied to RAM.
reloc2()
MyRoutine:
MyRoutineSMC $+1
ld hl,9999
dec hl
ld (MyRoutineSMC),hl
ld a,h
or l
jp nz,MyRoutine
ret
endreloc2()
And most importantly, to make sure the memory is actually allocated, you must call allocExtraRAM near the beginning of your program to format and copy the routines to RAM, and call deallocExtraRAM to clean up memory right before you exit.
My hope is that this is useful to someone. If not, blame geekboy. He convinced me to post this.