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:

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.
Oh, this is pretty nice! Smile I guess that I don't have to blame geekboy then. Razz This does make relocation many times easier, which is somethings that can be pretty annoying for sure. Good work Iambian! Smile
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement