Commit 4a30b643 authored by Jeffrey Lee's avatar Jeffrey Lee
Browse files

Improve heap manager. Add heap testbed. Add dummy implementation of some...

Improve heap manager. Add heap testbed. Add dummy implementation of some OS_ScreenMode reason codes.

Detail:
  s/HeapMan, hdr/KernelWS - Heap manager improvements:
    - Errors generated by interrupted heap operations that are forced to complete by a OS_Heap call from the background are now cached in kernel workspace until the foreground task is resumed. This prevents them from being potentially overwritten by MessageTrans running out of background error buffers.
    - Added new OS_Heap reason code, #7 - Get area aligned. This allows areas of memory to be allocated at specific (power-of-2) alignments, and optionally without crossing a given (power-of-2) boundary. Alignment & boundary calculations are performed using logical addresses.
    - Removed the limitation that all free and allocated blocks must be a multiple of 8 bytes in length. This change was required in order to allow OS_Heap 7 to function correctly. Now the only requirements are that blocks must be multiples of 4 bytes in length, at 4 byte alignment, with a minimum length of 8 bytes. 4 extra padding bytes may still be added to the end of allocations in order to avoid creating 4-byte free blocks.
  s/HeapMan, TestSrc/HeapTest/Makefile, TestSrc/HeapTest/c/testbed, TestSrc/HeapTest/s/asm - Added heap testbed program. Can either use the OS_Heap SWI or directly include a copy of the Kernel's heap manager sources.
  s/vdudecl, s/vduswis - Added dummy implementations of OS_ScreenMode 4, 5 and 6. This prevents the Wimp generating lots of "Unknown OS_ScreenMode reason code" errors when redrawing the screen.
  s/Arthur3, s/Oscli - Moved dotstring closer to where it's used to avoid "ADRL out of range" errors in Tungsten build
Admin:
  Tested in OMAP3 ROM & Tungsten ROM softload.
  Heap testbed successfully performed over 400 million heap ops, so there shouldn't be any serious bugs in the new code (touch wood)


Version 5.35, 4.79.2.128. Tagged as 'Kernel-5_35-4_79_2_128'
parent 189b92c1
# Copyright 2011 Castle Technology Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
COMPONENT = HeapTest
OBJS = asm testbed
include CApp
# Dynamic dependencies:
/* Copyright 2011 Castle Technology Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* OS_Heap testbed code. Creates a heap and randomly allocates/deallocates/
resizes blocks of memory to test for any bugs. Tests can either be performed
using the OS_Heap SWI or by compiling a special version of the heap code
from the kernel source folder (see USE_LOCAL_OSHEAP #define and s.asm)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include "kernel.h"
#include "swis.h"
#include "Global/Heap.h"
#include "Global/NewErrors.h"
/* Whether to use the XOS_Heap SWI or the local copy of the heap code */
#define USE_LOCAL_OSHEAP
/* Maximum number of allocations to make */
#define MAX_ALLOCS 1024
#define VBIT (1<<28)
#ifdef USE_LOCAL_OSHEAP
extern _kernel_oserror *CallHeap(_kernel_swi_regs *r);
#else
#define CallHeap(R) _kernel_swi(OS_Heap,R,R)
#endif
/* Workspace */
static uint32_t *heap=NULL; /* Main heap */
static uint32_t *backup=NULL; /* Backup copy of heap */
static uint32_t allocsize=0; /* Heap memory block size */
static uint32_t *usedspace=NULL; /* Bitmap of used space; 1 bit per word */
static uint32_t seed=0; /* RNG seed */
static uint32_t sequence=0; /* Number of ops performed */
static uint32_t numblocks=0; /* Number of blocks currently allocated */
static uint32_t blocks[MAX_ALLOCS]; /* Offsets of blocks within heap */
static uint32_t currentop = 0; /* Current heap operation */
static uint32_t opsleft = 0; /* Number of ops left */
static _kernel_swi_regs r;
static _kernel_swi_regs last;
/* Utility functions */
static void init(void)
{
srand(seed);
printf("Seed %08x alloc size %08x\n",seed,allocsize);
/* Make heap 4K aligned */
heap = (uint32_t *) (((uint32_t) malloc(allocsize+4096)+4095)&0xfffff000);
/* Same for backup */
backup = (uint32_t *) (((uint32_t) malloc(allocsize+4096)+4095)&0xfffff000);
/* Used space map */
usedspace = (uint32_t *) malloc(((allocsize+31*4)>>7)<<2);
memset(usedspace,0,((allocsize+31*4)>>7)<<2);
memset(heap,0,allocsize);
memset(backup,0,allocsize);
}
static uint32_t getrand(uint32_t max)
{
uint64_t temp = ((uint64_t) max)*rand();
return (uint32_t) (temp/RAND_MAX);
}
static void dumpheap(uint32_t *h)
{
fprintf(stderr,"heap @ %p:\nmag %x\nfree %x\nbase %x\nend %x\n",h,h[0],h[1],h[2],h[3]);
uint32_t free = h[1];
uint32_t next = 16;
if(free)
free += 4;
while(free)
{
if(free > next)
{
fprintf(stderr,"allocs between %x and %x:\n",next,free);
do {
fprintf(stderr,"%x: alloc size %x\n",next,h[next>>2]);
if((h[next>>2] > h[2]) || (h[next>>2]+next > h[2]) || (h[next>>2]&3) || !h[next>>2])
{
fprintf(stderr,"bad block, skipping rest\n");
break;
}
next += h[next>>2];
} while(free>next);
if(free!=next)
fprintf(stderr,"alloc mismatch! next=%x\n",next);
}
fprintf(stderr,"%x: free size %x next %x\n",free,h[(free+4)>>2],h[free>>2]);
if(h[(free+4)>>2] == h[free>>2])
fprintf(stderr,"consecutive free blocks!\n");
next = free+h[(free+4)>>2];
if((h[free>>2] & 3) || (h[free>>2] >= h[2]) || (h[free>>2]+free >= h[2]))
{
fprintf(stderr,"bad next ptr\n");
return;
}
if((h[(free+4)>>2] & 3) || (h[(free+4)>>2] >= h[2]) || (h[(free+4)>>2]+free >= h[2]))
{
fprintf(stderr,"bad size\n");
return;
}
if(!h[free>>2])
{
fprintf(stderr,"end of free list\n");
break;
}
free = free+h[free>>2];
if(free<next)
{
fprintf(stderr,"next free is inside current?\n");
return;
}
}
if(free > h[2])
{
fprintf(stderr,"free list extends beyond heap end\n");
}
if(next > h[2])
{
fprintf(stderr,"next ptr beyond heap end\n");
}
fprintf(stderr,"end allocs:\n");
while(next < h[2])
{
fprintf(stderr,"%x: alloc size %x\n",next,h[next>>2]);
if((h[next>>2] > h[2]) || (h[next>>2]+next > h[2]) || (h[next>>2]&3) || !h[next>>2])
{
fprintf(stderr,"bad block, skipping rest\n");
return;
}
next += h[next>>2];
}
fprintf(stderr,"end\n");
}
static bool heapvalid(uint32_t *h)
{
uint32_t free = h[1];
uint32_t next = 16;
if(free)
free += 4;
while(free)
{
if(free > next)
{
do {
if((h[next>>2] > h[2]) || (h[next>>2]+next > h[2]) || (h[next>>2]&3) || !h[next>>2])
{
return false;
}
next += h[next>>2];
} while(free>next);
if(free!=next)
return false;
}
if(h[(free+4)>>2] == h[free>>2])
return false;
next = free+h[(free+4)>>2];
if((h[free>>2] & 3) || (h[free>>2] >= h[2]) || (h[free>>2]+free >= h[2]))
{
return false;
}
if((h[(free+4)>>2] & 3) || (h[(free+4)>>2] >= h[2]) || (h[(free+4)>>2]+free >= h[2]))
{
return false;
}
if(!h[free>>2])
{
break;
}
free = free+h[free>>2];
if(free<next)
{
return false;
}
}
if(free > h[2])
{
return false;
}
if(next > h[2])
{
return false;
}
while(next < h[2])
{
if((h[next>>2] > h[2]) || (h[next>>2]+next > h[2]) || (h[next>>2]&3) || !h[next>>2])
{
return false;
}
next += h[next>>2];
}
return true;
}
static void fail(void)
{
fprintf(stderr,"Failed on sequence %d\n",sequence);
fprintf(stderr,"Last op registers:\n");
for(int i=0;i<5;i++)
fprintf(stderr,"r%d = %08x\n",i,last.r[i]);
fprintf(stderr,"Result registers:\n");
for(int i=0;i<5;i++)
fprintf(stderr,"r%d = %08x\n",i,r.r[i]);
fprintf(stderr,"Heap before op:\n");
dumpheap(backup);
fprintf(stderr,"Heap after op:\n");
dumpheap(heap);
fprintf(stderr,"Allocated blocks:\n");
for(uint32_t i=0;i<numblocks;i++)
{
fprintf(stderr,"%08x\n",blocks[i]);
}
exit(1);
}
static uint32_t blocksize(uint32_t offset)
{
return heap[(offset-4)>>2];
}
static void tryuse(uint32_t offset)
{
uint32_t len = blocksize(offset);
if((len-4 > allocsize-offset) || (len & 3) || (len<4))
{
fprintf(stderr,"tryuse: Bad block at %08x\n",offset);
fail();
}
offset >>= 2;
while(len)
{
if(usedspace[offset>>5] & (1<<(offset&31)))
{
fprintf(stderr,"tryuse: Overlapping block at %08x\n",offset<<2);
fail();
}
usedspace[offset>>5] |= 1<<(offset&31);
offset++;
len -= 4;
}
}
static void tryfree(uint32_t offset)
{
uint32_t len = blocksize(offset);
if((len-4 > allocsize-offset) || (len & 3) || (len<4))
{
fprintf(stderr,"tryfree: Bad block at %08x\n",offset);
fail();
}
offset >>= 2;
while(len)
{
if(!(usedspace[offset>>5] & (1<<(offset&31))))
{
fprintf(stderr,"tryfree: Block at %08x already freed\n",offset<<2);
fail();
}
usedspace[offset>>5] -= 1<<(offset&31);
offset++;
len -= 4;
}
}
/* Main function */
int main(int argc,char **argv)
{
_kernel_oserror *err;
/* TODO - Take parameters from command line */
_swix(OS_ReadMonotonicTime,_OUT(0),&seed)
allocsize = 8*1024;
init();
/* Initialise heap */
r.r[0] = HeapReason_Init;
r.r[1] = (int) heap;
r.r[3] = allocsize;
err = CallHeap(&r);
if(err)
{
fprintf(stderr,"Heap initialise failed! %s\n",err->errmess);
exit(1);
}
usedspace[0] = 0xf;
/* Begin tests */
uint32_t temp,temp2,temp3,temp4;
while(heapvalid(heap))
{
if(!opsleft)
{
opsleft = getrand(128);
switch(getrand(4))
{
case 0:
currentop = HeapReason_Get;
break;
case 1:
currentop = HeapReason_Free;
break;
case 2:
currentop = HeapReason_ExtendBlock;
break;
default:
currentop = HeapReason_GetAligned;
break;
}
}
if(!(sequence&0xffff))
{
// printf(".");
dumpheap(heap);
}
sequence++;
r.r[0] = currentop;
memcpy(backup,heap,allocsize);
switch(currentop)
{
case HeapReason_Get:
if(numblocks == MAX_ALLOCS)
{
opsleft = 0;
break;
}
r.r[3] = temp = getrand(allocsize>>5)+1;
last = r;
err = CallHeap(&r);
if(err)
{
if(err->errnum != ErrorNumber_HeapFail_Alloc)
{
fprintf(stderr,"Failed allocating %08x bytes: %s\n",temp,err->errmess);
fail();
}
}
else
{
temp2 = blocks[numblocks++] = r.r[2]-((uint32_t)heap);
if(blocksize(temp2) < temp+4)
{
fprintf(stderr,"Failed to allocate requested block size: %08x bytes at %08x\n",temp,temp2);
fail();
}
tryuse(temp2);
}
break;
case HeapReason_Free:
if(!numblocks)
{
opsleft = 0;
break;
}
temp = getrand(numblocks);
r.r[2] = blocks[temp]+((uint32_t) heap);
tryfree(blocks[temp]); /* Must free beforehand */
last = r;
err = CallHeap(&r);
if(err)
{
fprintf(stderr,"Failed freeing block at %08x: %s\n",blocks[temp],err->errmess);
fail();
}
blocks[temp] = blocks[--numblocks];
break;
case HeapReason_ExtendBlock:
if(!numblocks)
{
opsleft = 0;
break;
}
temp = getrand(numblocks);
r.r[2] = blocks[temp]+((uint32_t) heap);
temp2 = getrand(allocsize>>4)-(allocsize>>5);
r.r[3] = temp2;
temp3 = blocksize(blocks[temp]);
tryfree(blocks[temp]); /* Must free beforehand */
last = r;
err = CallHeap(&r);
if(err)
{
if(err->errnum != ErrorNumber_HeapFail_Alloc)
{
fprintf(stderr,"Failed resizing block at %08x by %08x bytes: %s\n",blocks[temp],(int) temp2,err->errmess);
fail();
}
if(blocksize(blocks[temp]) != temp3)
{
fprintf(stderr,"Resize failed but block size changed\n");
fail();
}
tryuse(blocks[temp]);
}
else
{
if(r.r[2] && (r.r[2] != 0xffffffff))
{
if((int) (temp3+temp2) <= 4)
{
fprintf(stderr,"Resized block was kept when it should have been freed: block %08x by %08x\n",blocks[temp],(int) temp2);
fail();
}
blocks[temp] = r.r[2]-((uint32_t)heap);
tryuse(blocks[temp]);
if((blocksize(blocks[temp])-(temp3+temp2)) > 7)
{
fprintf(stderr,"Failed to resize block by required amount: block %08x by %08x\n",blocks[temp],(int) temp2);
fail();
}
}
else
{
if((int) (temp3+temp2) > 4)
{
fprintf(stderr,"Resized block was freed when it should have remained: block %08x by %08x\n",blocks[temp],(int) temp2);
fail();
}
blocks[temp] = blocks[--numblocks];
}
}
break;
case HeapReason_GetAligned:
if(numblocks == MAX_ALLOCS)
{
opsleft = 0;
break;
}
r.r[3] = temp = getrand(allocsize>>4)+1;
temp2 = 4<<getrand(9); /* Max 2K alignment (heap 4K aligned) */
temp3 = temp2*(1<<getrand(5));
if(temp3 > 4096) /* Max 2K boundary (heap 4K aligned) */
temp3 = 2048;
if(temp3 < temp)
temp3 = 0;
r.r[2] = temp2;
r.r[4] = temp3;
last = r;
err = CallHeap(&r);
if(err)
{
if(err->errnum != ErrorNumber_HeapFail_Alloc)
{
fprintf(stderr,"Failed allocating %08x bytes at alignment %08x boundary %08x: %s\n",temp,temp2,temp3,err->errmess);
fail();
}
}
else
{
temp4 = blocks[numblocks++] = r.r[2]-((uint32_t) heap);
if(blocksize(temp4) < temp+4)
{
fprintf(stderr,"Failed to allocate requested block size: %08x bytes at alignment %08x boundary %08x at %08x\n",temp,temp2,temp3,temp4);
fail();
}
if(temp4 & (temp2-1))
{
fprintf(stderr,"Block allocated at wrong alignment: %08x bytes at alignment %08x boundary %08x at %08x\n",temp,temp2,temp3,temp4);
fail();
}
if(temp3 && ((temp4 & ~(temp3-1)) != ((temp4+temp-1) & ~(temp3-1))))
{
fprintf(stderr,"Block crosses boundary: %08x bytes at alignment %08x boundary %08x at %08x\n",temp,temp2,temp3,temp4);
fail();
}
tryuse(temp4);
}
break;
}
if(opsleft)
opsleft--;
}
fprintf(stderr,"Heap corruption detected!\n");
fail();
return 0;
}
; Copyright 2011 Castle Technology Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
; http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
; Assembler gubbins to allow a local copy of the heap manager to be used by
; the testbed application
GET Hdr:ListOpts
GET Hdr:Macros
GET Hdr:System
GET Hdr:CPU.Arch
GET Hdr:Machine.<Machine>
GET Hdr:Heap
GET Hdr:Proc
GET Hdr:FSNumbers
GET Hdr:HighFSI
GET Hdr:NewErrors
; Disable internationalisation
GBLL International
International SETL {FALSE}
; Indicate we're compiling the testbed
GBLL HeapTestbed
HeapTestbed SETL {TRUE}
; Heap debugging disabled for now
GBLL DebugHeaps
DebugHeaps SETL {FALSE}
; Fake zero page workspace
^ 0
IRQsema # 4
HeapSavedReg_R0 # 4
HeapSavedReg_R1 # 4
HeapSavedReg_R2 # 4
HeapSavedReg_R3 # 4
HeapSavedReg_R4 # 4
HeapSavedReg_R13 # 4
HeapReturnedReg_R0 # 4
HeapReturnedReg_R1 # 4
HeapReturnedReg_R2 # 4
HeapReturnedReg_R3 # 4
HeapReturnedReg_R4 # 4
HeapReturnedReg_R13 # 4
HeapReturnedReg_PSR # 4
ZeroPageSize * @
; Macros and other bits
MACRO
assert $condition
[ :LNOT: ($condition)
! 1,"Assert failed: $condition"
]
MEND
SVC2632 * SVC32_mode
AREA testbeddata, DATA
ZeroPage % ZeroPageSize
HeapBackgroundError % 256
AREA testbedcode, CODE
; C interface
EXPORT CallHeap
CallHeap ROUT
; r0 = _kernel_swi_regs ptr for input/output
; Returns error ptr in r0
Push "r0,r4-r11,lr"
LDMIA r0,{r0-r9}
SWI OS_EnterOS ; Call in SVC mode?
BL DoCallXOSHeap
MOVVS r10,r0
MOVVC r10,#0
SWI OS_LeaveOS
Pull "r11"
STMIA r11,{r0-r9}
MOV r0,r10
Pull "r4-r11,pc"
; Assembler bits for use by heap code
DoCallXOSHeap
; Fake an XOS_Heap SWI
; Preserve r10-r12 and enter with PSR in lr
Push "r10-r12,lr"
MRS lr,CPSR
B HeapEntry
; Main heap manager code
GET ^.^.s.HeapMan
END
......@@ -13,11 +13,11 @@
GBLS Module_ComponentPath
Module_MajorVersion SETS "5.35"
Module_Version SETA 535
Module_MinorVersion SETS "4.79.2.127"
Module_Date SETS "27 Nov 2011"
Module_ApplicationDate SETS "27-Nov-11"
Module_MinorVersion SETS "4.79.2.128"
Module_Date SETS "10 Dec 2011"
Module_ApplicationDate SETS "10-Dec-11"
Module_ComponentName SETS "Kernel"
Module_ComponentPath SETS "castle/RiscOS/Sources/Kernel"
Module_FullVersion SETS "5.35 (4.79.2.127)"
Module_HelpVersion SETS "5.35 (27 Nov 2011) 4.79.2.127"
Module_FullVersion SETS "5.35 (4.79.2.128)"
Module_HelpVersion SETS "5.35 (10 Dec 2011) 4.79.2.128"
END
......@@ -5,19 +5,19 @@
*
*/
#define Module_MajorVersion_CMHG 5.35
#define Module_MinorVersion_CMHG 4.79.2.127
#define Module_Date_CMHG 27 Nov 2011
#define Module_MinorVersion_CMHG 4.79.2.128
#define Module_Date_CMHG 10 Dec 2011
#define Module_MajorVersion "5.35"
#define Module_Version 535
#define Module_MinorVersion "4.79.2.127"
#define Module_Date "27 Nov 2011"
#define Module_MinorVersion "4.79.2.128"
#define Module_Date "10 Dec 2011"
#define Module_ApplicationDate "27-Nov-11"
#define Module_ApplicationDate "10-Dec-11"
#define Module_ComponentName "Kernel"
#define Module_ComponentPath "castle/RiscOS/Sources/Kernel"
#define Module_FullVersion "5.35 (4.79.2.127)"
#define Module_HelpVersion "5.35 (27 Nov 2011) 4.79.2.127"
#define Module_FullVersion "5.35 (4.79.2.128)"
#define Module_HelpVersion "5.35 (10 Dec 2011) 4.79.2.128"
#define Module_LibraryVersionInfo "5:35"
......@@ -1980,6 +1980,8 @@ ROMBuildDate # 128
NewFX0Error # 64
]
HeapBackgroundError # 256 ; For storing errors generated in the background by the forced completion of a foreground heap op
KbuffsEnd # 0
KbuffsSize * KbuffsEnd - KbuffsBaseAddress ;size of Kernel buffers area
......
......@@ -1545,6 +1545,8 @@ ReadNumAuto Entry "r1,r3,r4"
AutoString
= "Auto", 0
dotstring
= ".", 0
ALIGN
ReadSizeParm ROUT
......
This diff is collapsed.
......@@ -547,8 +547,7 @@ AliasOscliTooLong
AliasStr_QA = "ALIAS$", 0
]
AliasStr = "Alias$*", 0
AliasDot = "Alias$"
dotstring = ".", 0
AliasDot = "Alias$.", 0
ALIGN
[ Oscli_QuickAliases
......
......@@ -68,7 +68,10 @@ ScreenModeReason_SelectMode * 0
ScreenModeReason_ReturnMode * 1
ScreenModeReason_EnumerateModes * 2
ScreenModeReason_SelectMonitorType * 3
ScreenModeReason_Limit * 4
ScreenModeReason_ConfigureAcceleration * 4
ScreenModeReason_CleanCache * 5
ScreenModeReason_ForceCleanCache * 6
ScreenModeReason_Limit * 7
; Mode selector format
......
......@@ -1933,7 +1933,10 @@ ScreenModeSWI Entry
ASSERT ScreenModeReason_ReturnMode = 1
ASSERT ScreenModeReason_EnumerateModes = 2
ASSERT ScreenModeReason_SelectMonitorType = 3
ASSERT ScreenModeReason_Limit = 4
ASSERT ScreenModeReason_ConfigureAcceleration = 4
ASSERT ScreenModeReason_CleanCache = 5
ASSERT ScreenModeReason_ForceCleanCache = 6
ASSERT ScreenModeReason_Limit = 7
ScreenModeSub
CMP r0, #ScreenModeReason_Limit
......@@ -1943,6 +1946,9 @@ ScreenModeSub
B ScreenMode_ReturnMode
B ScreenMode_EnumerateModes
B ScreenMode_SelectMonitorType
B ScreenMode_ConfigureAcceleration
B ScreenMode_CleanCache
B ScreenMode_ForceCleanCache
; unknown OS_ScreenMode reason code
......@@ -2063,6 +2069,52 @@ ScreenMode_SelectMonitorType Entry "r0"
STR r1, [WsPtr, #CurrentMonitorType] ; update current value
EXIT
;**************************************************************************
;
; ScreenMode_ConfigureAcceleration - Configure screen memory cacheability
;
; Internal routine called by ScreenModeSWI
;
; in: r0 = reason code (4)
; r1 = flags:
; bit 0 : set to suspend cached screen until mode change
; bit 1 : set to suspend screen cleaning
; bit 2 : set to disable hardware acceleration
; other : reserved, must be 0
; or -1 to read current value
; r2 = number of VSyncs between automatic screen cleaning (1-3), or -1
; to read current value
;
; out: r1 = new flag state
; r2 = new number of VSyncs between automatic screen cleaning
; r10-r12 may be corrupted
; All other registers preserved
;
ScreenMode_ConfigureAcceleration
; Screen caching isn't supported yet. Just return dummy values.
MOV r1,#1
MOV r2,#1
MOV pc,lr
;**************************************************************************
;
; ScreenMode_CleanCache - Clean screen memory from cache, if cache enabled
; ScreenMode_ForceCleanCache - Force clean of screen memory from cache
;
; Internal routine called by ScreenModeSWI
;
; in: r0 = reason code (5 or 6)
;
; out: r10-r12 may be corrupted
; All other registers preserved
;
ScreenMode_CleanCache
ScreenMode_ForceCleanCache
; Screen caching isn't supported yet. Just do nothing.
MOV pc,lr
;;;mjsHAL - VIDCDividerSWI is horrible VIDC specific API, compiled out
;;;
; Should not cause any problems on any machine. STB flag just to be safe though.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment