Hamazing/source/framework/framework_memory.asm
chrisly42 9c48c11cd1 Big "squashed" update to latest version of Framework.
- Bugfix: WaitForFrame was completely broken. Now also caters for race-condition that would have waited one extra frame.
- Bugfix: InitPart would overwrite innocent memory (reported by Gigabates and Losso)
- Bugfix: Palette LERP had wrong bias.
- Removed extra paths in include statement, use default include paths instead
- Added Raspberry Casket no-jitter background calc mode (FW_MUSIC_PLAYER_CHOICE = 6)
- Updated Raspberry Casket to V2.0 presto branch (WIP)
- Removed fw_FrameCounterLong, use fw_FrameCounter-2 for debug purposes
- Support for blue noise palette LERPing (like in Is Real). Provide your own blue noise table (4 KB), stuff it into fw_BlueNoiseTablePtr, set FW_PALETTE_LERP_SUPPORT to 2
- Music tick routine is now replaceable during runtime (fw_MusicTickRoutine)
- Support for softints and audio interrupts
- LMB exit can also be disabled dynamically when using FW_LMB_EXIT_SUPPORT = 2 and fw_DisableLMBExit != 0
- Added LSP Micro support and LSP Nano (custom format that uses note pitches instead of periods)
- Minor other things
2024-09-15 17:43:33 +02:00

535 lines
17 KiB
NASM

;--------------------------------------------------------------------
DEBUGMEM MACRO
IFGE DEBUG_DETAIL-10
bsr fw_DebugMemoryManagement
ENDC
ENDM
;--------------------------------------------------------------------
; Initializes the memory stacks for chip- and fast-mem
;
fw_InitMemoryManagement:
move.l fw_ChipMemStack(a6),d0
move.l fw_ChipMemStackEnd(a6),d1
move.l fw_FastMemStack(a6),d2
move.l fw_FastMemStackEnd(a6),d3
PUTMSG 10,<"Chipmem %p - %p, Fastmem %p - %p">,d0,d1,d2,d3
lea fw_MemBottomStack(a6),a1
move.l d0,cf_ChipMemLevel+mtb_CurrLevelPtr(a1)
move.l d0,cf_ChipMemLevel+mtb_MinLevelPtr(a1)
move.l d2,cf_FastMemLevel+mtb_CurrLevelPtr(a1)
move.l d2,cf_FastMemLevel+mtb_MinLevelPtr(a1)
;clr.w fw_CurrMemBottomLevel(a6)
lea fw_MemTopStack(a6),a1
move.l d1,cf_ChipMemLevel+mtb_CurrLevelPtr(a1)
move.l d1,cf_ChipMemLevel+mtb_MinLevelPtr(a1)
move.l d3,cf_FastMemLevel+mtb_CurrLevelPtr(a1)
move.l d3,cf_FastMemLevel+mtb_MinLevelPtr(a1)
;clr.w fw_CurrMemTopLevel(a6)
DEBUGMEM
rts
;--------------------------------------------------------------------
; Frees all allocated memory
;
; Frees the memory of the current stack and current direction.
; Memory of other allocation direction is unchanged.
;
fw_DropCurrentMemoryAllocations:
PUTMSG 10,<"%d: DropCurrentMemoryAllocations">,fw_FrameCounter-2(a6)
IFGE DEBUG_DETAIL-20
PUSHM a0/a1/d0
ELSE
PUSHM a1
ENDC
DEBUGMEM
IF FW_TOP_BOTTOM_MEM_SECTIONS
bsr fw_DetectAllocationDirection
bne.s .toptobottom
ENDC
PUTMSG 10,<"DOWN: Freeing all">
lea fw_MemBottomStack(a6),a1
adda.w fw_CurrMemBottomLevel(a6),a1
IFGE DEBUG_DETAIL-20
move.l cf_ChipMemLevel+mtb_MinLevelPtr(a1),a0
move.l cf_ChipMemLevel+mtb_CurrLevelPtr(a1),d0
sub.l a0,d0
bsr fw_FillWithGarbage
move.l cf_FastMemLevel+mtb_MinLevelPtr(a1),a0
move.l cf_FastMemLevel+mtb_CurrLevelPtr(a1),d0
sub.l a0,d0
bsr fw_FillWithGarbage
ENDC
.cont
move.l cf_ChipMemLevel+mtb_MinLevelPtr(a1),cf_ChipMemLevel+mtb_CurrLevelPtr(a1)
move.l cf_FastMemLevel+mtb_MinLevelPtr(a1),cf_FastMemLevel+mtb_CurrLevelPtr(a1)
DEBUGMEM
POPM
rts
IF FW_TOP_BOTTOM_MEM_SECTIONS
.toptobottom
PUTMSG 10,<"UP: Freeing all">
lea fw_MemTopStack(a6),a1
adda.w fw_CurrMemTopLevel(a6),a1
IFGE DEBUG_DETAIL-20
move.l cf_ChipMemLevel+mtb_CurrLevelPtr(a1),a0
move.l cf_ChipMemLevel+mtb_MinLevelPtr(a1),d0
sub.l a0,d0
bsr fw_FillWithGarbage
move.l cf_FastMemLevel+mtb_CurrLevelPtr(a1),a0
move.l cf_FastMemLevel+mtb_MinLevelPtr(a1),d0
sub.l a0,d0
bsr fw_FillWithGarbage
ENDC
bra.s .cont
ENDC
;--------------------------------------------------------------------
; Pushes the current memory allocation state to the stack
;
; This only pushes the state for the current memory allocation
; direction onto the stack. All allocated memory upto this point
; will be kept safe and will no longer be freed automatically.
;
fw_PushMemoryState:
PUSHM a1/d0-d1
moveq.l #cf_SIZEOF,d0
IF FW_TOP_BOTTOM_MEM_SECTIONS
bsr fw_DetectAllocationDirection
bne.s .toptobottom
ENDC
PUTMSG 10,<"UP: ++++++ Pushing mem state ++++++">
add.w fw_CurrMemBottomLevel(a6),d0
move.w d0,fw_CurrMemBottomLevel(a6)
lea fw_MemBottomStack(a6,d0.w),a1
.cont
move.l cf_ChipMemLevel+mtb_CurrLevelPtr-cf_SIZEOF(a1),d0
move.l cf_FastMemLevel+mtb_CurrLevelPtr-cf_SIZEOF(a1),d1
move.l d0,cf_ChipMemLevel+mtb_CurrLevelPtr(a1)
move.l d0,cf_ChipMemLevel+mtb_MinLevelPtr(a1)
move.l d1,cf_FastMemLevel+mtb_CurrLevelPtr(a1)
move.l d1,cf_FastMemLevel+mtb_MinLevelPtr(a1)
DEBUGMEM
POPM
rts
IF FW_TOP_BOTTOM_MEM_SECTIONS
.toptobottom
PUTMSG 10,<"DOWN: ++++++ Pushing mem state ++++++">
add.w fw_CurrMemTopLevel(a6),d0
move.w d0,fw_CurrMemTopLevel(a6)
lea fw_MemTopStack(a6,d0.w),a1
bra.s .cont
ENDC
;--------------------------------------------------------------------
; Restore the last memory state from the memory stack for the current
; allocation direction. All memory from the previous allocation is
; freed.
;
; With debug enabled, freed memory is also overwritten with garbage.
;
; Out: All registers unchanged.
;
fw_PopMemoryState:
PUSHM a0/d0
DEBUGMEM
IF FW_TOP_BOTTOM_MEM_SECTIONS
bsr fw_DetectAllocationDirection
bne .toptobottom
ENDC
IFGE DEBUG_DETAIL-10
PUTMSG 10,<"UP: ------ Popping mem state ------">
bsr fw_DropCurrentMemoryAllocations
sub.w #cf_SIZEOF,fw_CurrMemBottomLevel(a6)
bmi.s .errorbottom
ELSE
sub.w #cf_SIZEOF,fw_CurrMemBottomLevel(a6)
ENDC
.cont
DEBUGMEM
POPM
rts
IFGE DEBUG_DETAIL-10
.errorbottom
PUTMSG 10,<"!!! Could not pop bottom memory stack (TOP: %d vs %d)">,fw_CurrMemBottomLevel-2(a6),fw_CurrMemTopLevel-2(a6)
move.w #ERROR_MEMORYWRONGPOP,d0
bra fw_Error
.errortop
PUTMSG 10,<"!!! Could not pop top memory stack (TOP: %d vs %d)">,fw_CurrMemBottomLevel-2(a6),fw_CurrMemTopLevel-2(a6)
move.w #ERROR_MEMORYWRONGPOP,d0
bra fw_Error
ENDC
IF FW_TOP_BOTTOM_MEM_SECTIONS
.toptobottom
IFGE DEBUG_DETAIL-10
PUTMSG 10,<"DOWN: ------ Popping mem state ------">
bsr fw_DropCurrentMemoryAllocations
sub.w #cf_SIZEOF,fw_CurrMemTopLevel(a6)
bmi .errortop
ELSE
sub.w #cf_SIZEOF,fw_CurrMemTopLevel(a6)
ENDC
bra .cont
ENDC
;--------------------------------------------------------------------
; Allocates the given amount of fastmem in the current direction of
; memory allocation (bottom->top or top->bottom).
;
; If theres not enough fast-mem, it falls back and returns chip-mem
; instead.
;
; Contents of memory are not cleared!
;
; In : d0: Size in bytes
; Out: a0: Start of memory allocation
; d0: Rounded size of allocation
; d1/a1: Trashed.
;
fw_AllocFast:
PUTMSG 10,<"%d: AllocFast(%ld)">,fw_FrameCounter-2(a6),d0
addq.l #3,d0
and.w #-4,d0
lea fw_MemBottomStack(a6),a0
adda.w fw_CurrMemBottomLevel(a6),a0
lea fw_MemTopStack(a6),a1
adda.w fw_CurrMemTopLevel(a6),a1
move.l cf_FastMemLevel+mtb_CurrLevelPtr(a1),d1
sub.l cf_FastMemLevel+mtb_CurrLevelPtr(a0),d1
cmp.l d0,d1
blo.s fw_AllocChip
moveq.l #cf_FastMemLevel,d1
bsr fw_DoAllocation
PUTMSG 30,<"Fast allocated at %p">,a0
IFGE DEBUG_DETAIL-12
bsr.s fw_FillWithGarbage
ENDC
DEBUGMEM
rts
;--------------------------------------------------------------------
; Allocates the given amount of chipmem in the current direction of
; memory allocation (bottom->top or top->bottom).
;
; Contents of memory are not cleared!
;
; In : d0: Size in bytes
; Out: a0: Start of memory allocation
; d0: Rounded size of allocation
; d1/a1: Trashed.
;
fw_AllocChip:
PUTMSG 10,<"%d: AllocChip(%ld)">,fw_FrameCounter-2(a6),d0
addq.l #7,d0
and.w #-8,d0
lea fw_MemBottomStack(a6),a0
adda.w fw_CurrMemBottomLevel(a6),a0
lea fw_MemTopStack(a6),a1
adda.w fw_CurrMemTopLevel(a6),a1
move.l cf_ChipMemLevel+mtb_CurrLevelPtr(a1),d1
sub.l cf_ChipMemLevel+mtb_CurrLevelPtr(a0),d1
cmp.l d0,d1
blo.s .error
moveq.l #cf_ChipMemLevel,d1
bsr fw_DoAllocation
PUTMSG 30,<"Chip allocated at %p">,a0
IFGE DEBUG_DETAIL-12
bsr fw_FillWithGarbage
ENDC
DEBUGMEM
rts
.error
PUTMSG 10,<"Out of memory: %ld smaller than %ld">,d1,d0
DEBUGMEM
move.w #ERROR_OUTOFMEMORY,d0
bra fw_Error
;--------------------------------------------------------------------
; Allocates the given amount of chipmem within a 64 KB page in the
; current direction of memory allocation.
;
; Memory area returned is guaranteed not to cross a 64 KB page
; boundary for the given size. Depending on the current memory
; situation and size requirements, may waste up to 64 KB of memory
; in the worst case. If you need multiple allocations these
; requirements, make sure to cluster them in a good way.
;
; Contents of memory are not cleared!
;
; In : d0: Size in bytes (less or equal to 64 KB!)
; Out: a0: Start of memory allocation
; d0: Rounded size of allocation
; d1/a1: Trashed.
;
IF FW_64KB_PAGE_MEMORY_SUPPORT
fw_AllocChip64KB:
PUTMSG 10,<"%d: AllocChip64KB(%ld)">,fw_FrameCounter-2(a6),d0
addq.l #7,d0
and.w #-8,d0
lea fw_MemBottomStack(a6),a0
adda.w fw_CurrMemBottomLevel(a6),a0
lea fw_MemTopStack(a6),a1
adda.w fw_CurrMemTopLevel(a6),a1
.retry
move.l cf_ChipMemLevel+mtb_CurrLevelPtr(a1),d1
sub.l cf_ChipMemLevel+mtb_CurrLevelPtr(a0),d1
cmp.l d0,d1
blo .error
IF FW_TOP_BOTTOM_MEM_SECTIONS
bsr fw_DetectAllocationDirection
bne.s .toptobottom
ENDC
move.l cf_ChipMemLevel+mtb_CurrLevelPtr(a0),d1
add.l d0,d1
subq.l #1,d1
swap d1
cmp.w cf_ChipMemLevel+mtb_CurrLevelPtr(a0),d1
beq .doallocation
addq.w #1,cf_ChipMemLevel+mtb_CurrLevelPtr(a0)
IFGE DEBUG_DETAIL-10
moveq.l #0,d1
move.w cf_ChipMemLevel+mtb_CurrLevelPtr+2(a0),d1
neg.w d1
PUTMSG 10,<"Skipping %ld bytes of memory DOWN (sorry)">,d1
ENDC
clr.w cf_ChipMemLevel+mtb_CurrLevelPtr+2(a0)
bra.s .retry
IF FW_TOP_BOTTOM_MEM_SECTIONS
.toptobottom
moveq.l #0,d1
move.w cf_ChipMemLevel+mtb_CurrLevelPtr+2(a1),d1
beq.s .doallocation
cmp.l d0,d1
bge.s .doallocation
PUTMSG 10,<"Skipping %d bytes of memory UP (sorry)">,cf_ChipMemLevel+mtb_CurrLevelPtr(a1)
clr.w cf_ChipMemLevel+mtb_CurrLevelPtr+2(a1)
bra .retry
ENDC
.doallocation
moveq.l #cf_ChipMemLevel,d1
bsr fw_DoAllocation
PUTMSG 30,<"Chip within 64 KB page allocated at %p">,a0
IFGE DEBUG_DETAIL-20
bsr fw_FillWithGarbage
ENDC
DEBUGMEM
rts
.error
PUTMSG 10,<"Out of memory: %ld smaller than %ld">,d1,d0
DEBUGMEM
move.w #ERROR_OUTOFMEMORY,d0
bra fw_Error
ENDC
;--------------------------------------------------------------------
; Changes the direction of memory allocation (bottom to top vs top
; to bottom). Also works from subtasks (be a bit careful there).
;
; Out: All registers unchanged.
;
IF FW_TOP_BOTTOM_MEM_SECTIONS
fw_FlipAllocationDirection:
IF FW_MULTITASKING_SUPPORT
tst.l fw_BackgroundTask(a6)
beq.s .flipmain
PUSHM a0
move.l fw_BackgroundTask(a6),a0
eor.w #1,ft_MemDirection(a0)
PUTMSG 10,<"Flipping allocation direction of task %p (%s) to %d">,a0,LN_NAME(a0),ft_MemDirection-2(a0)
POPM
rts
ENDC
.flipmain
eor.w #1,fw_MainMemDirection(a6)
PUTMSG 10,<"Flipping main allocation direction to %d">,fw_MainMemDirection-2(a6)
rts
;--------------------------------------------------------------------
fw_DetectAllocationDirection:
IF FW_MULTITASKING_SUPPORT
tst.l fw_BackgroundTask(a6)
beq.s .flipmain
PUSHM a0/d0 ; avoid optimizing the movem to move so that the CCs remain intact
move.l fw_BackgroundTask(a6),a0
tst.w ft_MemDirection(a0)
POPM
rts
ENDC
.flipmain
tst.w fw_MainMemDirection(a6)
rts
ENDC
;--------------------------------------------------------------------
fw_DoAllocation:
PUSHM a1/d0/d1
IF FW_TOP_BOTTOM_MEM_SECTIONS
bsr fw_DetectAllocationDirection
bne.s .toptobottom
ENDC
; allocate from bottom
lea fw_MemBottomStack(a6),a1
adda.w fw_CurrMemBottomLevel(a6),a1
move.l mtb_CurrLevelPtr(a1,d1.w),a0
PUTMSG 10,<"UP: Allocating %ld bytes from bottom at %p">,d0,a0
add.l a0,d0
move.l d0,mtb_CurrLevelPtr(a1,d1.w)
.cont
POPM
rts
IF FW_TOP_BOTTOM_MEM_SECTIONS
.toptobottom
; allocate from top
lea fw_MemTopStack(a6),a1
adda.w fw_CurrMemTopLevel(a6),a1
move.l mtb_CurrLevelPtr(a1,d1.w),a0
sub.l d0,a0
PUTMSG 10,<"DOWN: Allocating %ld bytes from top at %p">,d0,a0
move.l a0,mtb_CurrLevelPtr(a1,d1.w)
bra.s .cont
ENDC
;--------------------------------------------------------------------
IFGE DEBUG_DETAIL-12
fw_FillWithGarbage:
PUTMSG 10,<"Filling with garbage %p (%ld)">,a0,d0
PUSHM a0/d0/d1
lsr.l #2,d0
beq.s .skipfill
subq.w #1,d0
move.l #$DEADBE00,d1
.fillloop
move.l d1,(a0)+
addq.l #1,d1
dbra d0,.fillloop
swap d0
subq.w #1,d0
bcs.s .skipfill
swap d0
bra.s .fillloop
.skipfill
POPM
rts
ENDC
;--------------------------------------------------------------------
IFGE DEBUG_DETAIL-10
fw_DebugMemoryManagement:
PUSHM d0-d7/a0/a1
lea fw_MemBottomStack(a6),a0
adda.w fw_CurrMemBottomLevel(a6),a0
lea fw_MemTopStack(a6),a1
adda.w fw_CurrMemTopLevel(a6),a1
move.l cf_ChipMemLevel+mtb_CurrLevelPtr(a1),d0 ; current free chip: chip top - bottom
sub.l cf_ChipMemLevel+mtb_CurrLevelPtr(a0),d0
lsr.l #8,d0
lsr.w #2,d0
move.l fw_MemTopStack+cf_ChipMemLevel+mtb_MinLevelPtr(a6),d1 ; max free chip within this frame
sub.l cf_ChipMemLevel+mtb_MinLevelPtr(a0),d1
lsr.l #8,d1
lsr.w #2,d1
move.l cf_ChipMemLevel+mtb_CurrLevelPtr(a0),d2 ; bottom chip allocated in stack
sub.l cf_ChipMemLevel+mtb_MinLevelPtr(a0),d2
lsr.l #8,d2
lsr.w #2,d2
move.l cf_ChipMemLevel+mtb_MinLevelPtr(a1),d3 ; top chip allocated in stack
sub.l cf_ChipMemLevel+mtb_CurrLevelPtr(a1),d3
lsr.l #8,d3
lsr.w #2,d3
move.l cf_FastMemLevel+mtb_CurrLevelPtr(a1),d4 ; current free fast: fast top - bottom
sub.l cf_FastMemLevel+mtb_CurrLevelPtr(a0),d4
lsr.l #8,d4
lsr.w #2,d4
move.l cf_FastMemLevel+mtb_MinLevelPtr(a1),d5 ; max free fast within this frame
sub.l fw_MemBottomStack+cf_FastMemLevel+mtb_MinLevelPtr(a6),d5
lsr.l #8,d5
lsr.w #2,d5
move.l cf_FastMemLevel+mtb_CurrLevelPtr(a0),d6 ; bottom fast allocated in stack
sub.l cf_FastMemLevel+mtb_MinLevelPtr(a0),d6
lsr.l #8,d6
lsr.w #2,d6
move.l cf_FastMemLevel+mtb_MinLevelPtr(a1),d7 ; top fast allocated in stack
sub.l cf_FastMemLevel+mtb_CurrLevelPtr(a1),d7
lsr.l #8,d7
lsr.w #2,d7
PUTMSG 10,<"Mem Free: Chip: %ld of %ld KB (%ld/%ld KB) | Fast: %ld of %ld KB (%ld/%ld KB)">,d0,d1,d2,d3,d4,d5,d6,d7
move.l cf_ChipMemLevel+mtb_CurrLevelPtr(a0),d0 ; bottom chip allocated total
sub.l fw_MemBottomStack+cf_ChipMemLevel+mtb_MinLevelPtr(a6),d0
add.l fw_MemTopStack+cf_ChipMemLevel+mtb_MinLevelPtr(a6),d0 ; top chip allocated total
sub.l cf_ChipMemLevel+mtb_CurrLevelPtr(a1),d0
lsr.l #8,d0
lsr.w #2,d0
cmp.l fw_MaxChipUsed(a6),d0
blt.s .lesschip
move.l d0,fw_MaxChipUsed(a6)
.lesschip
move.l fw_MemTopStack+cf_ChipMemLevel+mtb_MinLevelPtr(a6),d1 ; max free chip total
sub.l fw_MemBottomStack+cf_ChipMemLevel+mtb_MinLevelPtr(a6),d1
lsr.l #8,d1
lsr.w #2,d1
move.l cf_FastMemLevel+mtb_CurrLevelPtr(a0),d2 ; bottom fast allocated total
sub.l fw_MemBottomStack+cf_FastMemLevel+mtb_MinLevelPtr(a6),d2
add.l fw_MemTopStack+cf_FastMemLevel+mtb_MinLevelPtr(a6),d2 ; top fast allocated total
sub.l cf_FastMemLevel+mtb_CurrLevelPtr(a1),d2
lsr.l #8,d2
lsr.w #2,d2
cmp.l fw_MaxFastUsed(a6),d2
blt.s .lessfast
move.l d2,fw_MaxFastUsed(a6)
.lessfast
move.l fw_MemTopStack+cf_FastMemLevel+mtb_MinLevelPtr(a6),d3 ; max free fast total
sub.l fw_MemBottomStack+cf_FastMemLevel+mtb_MinLevelPtr(a6),d3
lsr.l #8,d3
lsr.w #2,d3
PUTMSG 10,<"Mem Used: Chip: %ld of %ld KB (max. %ld KB) | Fast: %ld of %ld KB (max. %ld KB)">,d0,d1,fw_MaxChipUsed(a6),d2,d3,fw_MaxFastUsed(a6)
PUTMSG 20,<"Chip Bottom: %p, Chip Top %p, Fast Bottom: %p, Fast Top: %p">,cf_ChipMemLevel+mtb_CurrLevelPtr(a0),cf_ChipMemLevel+mtb_CurrLevelPtr(a1),cf_FastMemLevel+mtb_CurrLevelPtr(a0),cf_FastMemLevel+mtb_CurrLevelPtr(a1)
POPM
rts
ENDC