From da847c792c26ee6888c66228eb25c026baf0eab5 Mon Sep 17 00:00:00 2001
From: Mike Stephens <mstephen@gitlab.riscosopen.org>
Date: Fri, 10 Nov 2000 14:41:16 +0000
Subject: [PATCH] reintroduce Ursula AMBControl, recoded with generic ARMop
 style, not debugged yet

Version 5.35, 4.79.2.12. Tagged as 'Kernel-5_35-4_79_2_12'
---
 VersionASM              |  16 +-
 VersionNum              |  19 +-
 hdr/KernelWS            |  27 +--
 hdr/Options             |   6 +
 s/AMBControl/AMB        |   7 +
 s/AMBControl/Memory     |  84 ++++----
 s/AMBControl/Options    |  48 ++++-
 s/AMBControl/Workspace  | 102 ++++++---
 s/AMBControl/allocate   |  39 +---
 s/AMBControl/deallocate |   6 +-
 s/AMBControl/growp      |  16 +-
 s/AMBControl/growshrink |  18 +-
 s/AMBControl/main       | 112 +++++++---
 s/AMBControl/mapslot    |  43 +++-
 s/AMBControl/memmap     | 460 ++++++++++++++++++++++++++--------------
 s/AMBControl/service    | 128 +++++++++--
 s/AMBControl/shrinkp    |  24 ++-
 s/ARMops                |  67 ++++++
 18 files changed, 861 insertions(+), 361 deletions(-)

diff --git a/VersionASM b/VersionASM
index 88c7f791..89a7571f 100644
--- a/VersionASM
+++ b/VersionASM
@@ -9,12 +9,16 @@
                         GBLS    Module_ApplicationDate2
                         GBLS    Module_ApplicationDate4
                         GBLS    Module_HelpVersion
+                        GBLS    Module_ComponentName
+                        GBLS    Module_ComponentPath
 Module_MajorVersion     SETS    "5.35"
 Module_Version          SETA    535
-Module_MinorVersion     SETS    "4.79.2.11"
-Module_Date             SETS    "20 Oct 2000"
-Module_ApplicationDate2 SETS    "20-Oct-00"
-Module_ApplicationDate4 SETS    "20-Oct-2000"
-Module_FullVersion      SETS    "5.35 (4.79.2.11)"
-Module_HelpVersion      SETS    "5.35 (20 Oct 2000) 4.79.2.11"
+Module_MinorVersion     SETS    "4.79.2.12"
+Module_Date             SETS    "10 Nov 2000"
+Module_ApplicationDate2 SETS    "10-Nov-00"
+Module_ApplicationDate4 SETS    "10-Nov-2000"
+Module_ComponentName    SETS    "Kernel"
+Module_ComponentPath    SETS    "RiscOS/Sources/Kernel"
+Module_FullVersion      SETS    "5.35 (4.79.2.12)"
+Module_HelpVersion      SETS    "5.35 (10 Nov 2000) 4.79.2.12"
                         END
diff --git a/VersionNum b/VersionNum
index f55412af..fccf4cfe 100644
--- a/VersionNum
+++ b/VersionNum
@@ -4,16 +4,19 @@
  *
  */
 #define Module_MajorVersion_CMHG        5.35
-#define Module_MinorVersion_CMHG        4.79.2.11
-#define Module_Date_CMHG                20 Oct 2000
+#define Module_MinorVersion_CMHG        4.79.2.12
+#define Module_Date_CMHG                10 Nov 2000
 
 #define Module_MajorVersion             "5.35"
 #define Module_Version                  535
-#define Module_MinorVersion             "4.79.2.11"
-#define Module_Date                     "20 Oct 2000"
+#define Module_MinorVersion             "4.79.2.12"
+#define Module_Date                     "10 Nov 2000"
 
-#define Module_ApplicationDate2         "20-Oct-00"
-#define Module_ApplicationDate4         "20-Oct-2000"
+#define Module_ApplicationDate2         "10-Nov-00"
+#define Module_ApplicationDate4         "10-Nov-2000"
 
-#define Module_FullVersion              "5.35 (4.79.2.11)"
-#define Module_HelpVersion              "5.35 (20 Oct 2000) (4.79.2.11)"
+#define Module_ComponentName            "Kernel"
+#define Module_ComponentPath            "RiscOS/Sources/Kernel"
+
+#define Module_FullVersion              "5.35 (4.79.2.12)"
+#define Module_HelpVersion              "5.35 (10 Nov 2000) (4.79.2.12)"
diff --git a/hdr/KernelWS b/hdr/KernelWS
index bbff4ad6..38a00650 100644
--- a/hdr/KernelWS
+++ b/hdr/KernelWS
@@ -1171,18 +1171,21 @@ ProcessorArch   #       1
 
                 AlignSpace
 
-Proc_Cache_CleanInvalidateAll   #       4
-Proc_Cache_CleanAll             #       4
-Proc_Cache_InvalidateAll        #       4
-Proc_TLB_InvalidateAll          #       4
-Proc_TLB_InvalidateEntry        #       4
-Proc_WriteBuffer_Drain          #       4
-Proc_IMB_Full                   #       4
-Proc_IMB_Range                  #       4
-Proc_MMU_Changing               #       4
-Proc_MMU_ChangingEntry          #       4
-Proc_MMU_ChangingUncached       #       4
-Proc_MMU_ChangingUncachedEntry  #       4
+Proc_Cache_CleanInvalidateAll     #       4
+Proc_Cache_CleanAll               #       4
+Proc_Cache_InvalidateAll          #       4
+Proc_Cache_RangeThreshold         #       4
+Proc_TLB_InvalidateAll            #       4
+Proc_TLB_InvalidateEntry          #       4
+Proc_WriteBuffer_Drain            #       4
+Proc_IMB_Full                     #       4
+Proc_IMB_Range                    #       4
+Proc_MMU_Changing                 #       4
+Proc_MMU_ChangingEntry            #       4
+Proc_MMU_ChangingUncached         #       4
+Proc_MMU_ChangingUncachedEntry    #       4
+Proc_MMU_ChangingEntries          #       4
+Proc_MMU_ChangingUncachedEntries  #       4
 
  ]
 
diff --git a/hdr/Options b/hdr/Options
index 80d86b60..e5d22e7d 100644
--- a/hdr/Options
+++ b/hdr/Options
@@ -236,6 +236,7 @@ ARM6support            SETL {TRUE}
                 ;despatch and wider SWI hashing)
                 ;
                 ;any ARM
+                ;
                 GBLL    ChocolateSysHeap        ;whether to save cost of SysHeap block claim/release for common cases (eg. callback blocks)
                                                 ;also reduces SysHeap stress by using fewer blocks in total
                 GBLL    ChocolateOSMod          ;whether to reduce SysHeap stress in module handling
@@ -244,11 +245,16 @@ ARM6support            SETL {TRUE}
                 GBLL    ChocolateService        ;whether to implement fast module service call distribution (uses table introduced
                                                 ;into module format by Ursula API
 
+                ;possibly enabled at run time for some ARMs only
+                ;
+                GBLL    ChocolateAMB            ;whether to compile support for Lazy task swapping
+
 ChocolateSysHeap       SETL {TRUE}
 ChocolateOSMod         SETL {TRUE}
 ChocolateSysVars       SETL {TRUE}
 ChocolateOscli         SETL {TRUE}
 ChocolateService       SETL {TRUE}
+ChocolateAMB           SETL {TRUE}
   [ ChocolateSysHeap
                        GBLA  MaxChocolateCBBlocks  ;max quick CallBack blocks available at any one time (else ordinary heap nodes used)
                        GBLA  MaxChocolateSVBlocks  ;max quick Software Vector blocks available at any one time (else ordinary heap nodes used)
diff --git a/s/AMBControl/AMB b/s/AMBControl/AMB
index 51de20a8..c0088427 100644
--- a/s/AMBControl/AMB
+++ b/s/AMBControl/AMB
@@ -13,6 +13,13 @@
 ; limitations under the License.
 ;
 
+; Implements OS_AMBControl (takes care of application memory management for Wimp)
+;
+; Nov 1995  mjs  development version originated as Module
+; Jul 1996  mjs  fully implemented in kernel for RISC OS 3.70
+; Mar 1997  mjs  performance enhancements for Ursula OS
+; Oct 2000  mjs  Ursula code resurrected for 32-bit HALised kernel, hoorah!
+
         GET     s.AMBControl.Options
         GET     s.AMBControl.Workspace
         GET     s.AMBControl.main
diff --git a/s/AMBControl/Memory b/s/AMBControl/Memory
index 043d7318..8fc2f47e 100644
--- a/s/AMBControl/Memory
+++ b/s/AMBControl/Memory
@@ -14,57 +14,47 @@
 ;
 ; > s.Memory
 
-; lifted from Wimp source (v3.67)
+; Small veneer between AMBControl's memory block requirements and OS_Heap,
+; using system heap. This is changed since Ursula - old code called OS_Module
+; and claimed blocks from RMA, which is an anachronism since code is in
+; the kernel.
 
-; this OS_Module equivalent looks at ptr-4 which the Heap Manager uses
-; to store the real size of the block. In this way the memory use is
-; more efficient (especially when extending a block) and RMA should
-; fragment less often.
-
-
-XROS_Module Entry
-        TEQ     R0,#6
-        TEQNE   R0,#7
-        TEQNE   R0,#13
-        SWINE   XOS_Module
-        EXIT    NE
-        TEQ     R0,#6
-        BEQ     ros_claim
-        TEQ     R0,#7
-        BEQ     ros_free
-; extend
-        Push    "R3-R5"
-        LDR     R4,[R2,#-8]
-        LDR     R5,[R2,#-4]!
-        ADD     R5,R5,R3                        ; R5 is proposed new size
-        SUB     R4,R4,#4
-        CMP     R4,R5
-        CMPGE   R3,#0
-        BLT     %FT02
-        STR     R5,[R2],#4                      ; enough space so just store
-        Pull    "R3-R5"
-; can never error
-        CLRV
-        EXIT
-02
-        SUB     R3,R5,R4
-        SWI     XOS_Module
-        STRVC   R5,[R2],#4
-        Pull    "R3-R5"
-        EXIT
+; quantise sizes to reduce heap stress
+;
+AMBblockQ  * 64
 
 
-ros_free
-        SUB     R2,R2,#4
-        SWI     XOS_Module
-        EXIT
+;in:  r3=size
+;out: r2 -> block, r0 corrupted
+;
+AMB_BlockClaim ROUT
+        Push    "r1,r3,lr"
+        ADD     r3,r3,#AMBblockQ - 1
+        BIC     r3,r3,#AMBblockQ - 1
+        BL      ClaimSysHeapNode
+        Pull    "r1,r3,pc"
+
+;in:  r2 -> block
+;out: r0 corrupted
+;
+AMB_BlockFree ROUT
+        Push    "r1,lr"
+        BL      FreeSysHeapNode
+        Pull    "r1,pc"
 
-ros_claim
-        ADD     R3,R3,#4
-        SWI     XOS_Module
-        STRVC   R3,[R2],#4                      ; so modptr-4 = amount asked for + 4
-        SUB     R3,R3,#4                        ; needs to be preserved
-        EXIT
+;in:  r2 -> block, r3 = new size
+;out: r2 -> new block, r0 corrupted
+;
+AMB_BlockResize ROUT
+        Push    "r1,r3,lr"
+        ADD     r3,r3,#AMBblockQ - 1
+        BIC     r3,r3,#AMBblockQ - 1
+        LDR     r1,[r2,#-4]                  ;pick up OS_Heap's size word (naughty!)
+        SUB     r1,r1,#8                     ;heap size will be 8 more than quantised size
+        SUBS    r3,r3,r1                     ;required size change
+        MOVNE   r0, #HeapReason_ExtendBlock
+        BLNE    DoSysHeapOpWithExtension
+        Pull    "r1,r3,pc"
 
 
         END
diff --git a/s/AMBControl/Options b/s/AMBControl/Options
index 185d552b..fc4c2424 100644
--- a/s/AMBControl/Options
+++ b/s/AMBControl/Options
@@ -13,10 +13,12 @@
 ; limitations under the License.
 ;
 
+; > s.Options
+
 AMBMagicNodeID     * &4E424D41        ;"AMBN"
 
 AMBInitialMaxNodes * 256
-AMBGrowMaxNodes    * 64
+AMBGrowMaxNodes    * 64               ;not used now AMBControl is in kernel
 
 
 ;Bin pages by physical address, for quick mapping from page number to
@@ -30,15 +32,49 @@ AMBPhysBinMask     * &7F
 
 
 ApplicationStart  * (32*1024)
-AbsMaxAppSize     * (28*1024*1024) ;28 Mb application space limit for RISC OS
 
-;maximum logical space size cleaned by range strategy
-;
-AMB_ARMA_CleanRange_thresh * 256*1024
+AbsMaxAppSize     * (28*1024*1024)                   ;28 Mb application space limit for RISC OS
+AbsMaxAppPages    * (AbsMaxAppSize:SHR:Log2PageSize) ;and same limit expressed in Pages
 
+  [ ChocolateAMB
+AMBMIRegWords      * (AbsMaxAppPages+31) :SHR: 5     ;no. of words for AMBMappedInRegister
+                                                     ;convenient to set this at fixed max size
+                                                     ;(only 896 bytes for 28Mb AppSpace)
+  ]
 
-                GBLL    ValidateAMBHandles     ; whether to check handles given to AppMAMBan
+;whether to check handles given to AMBControl - not very useful when in kernel
+;
+                    GBLL    ValidateAMBHandles
 ValidateAMBHandles  SETL    {FALSE}
 
 
+;performance enhancements originally introduced for Ursula OS
+;
+; ChocolateAMB       - if {FALSE}, disables all AMBControl crazy chocolate flavour enhancements
+;
+; AMB_LazyMapIn      - if {TRUE}, individual pages of a swapped-in task are only mapped in when
+;                      necessary (happens via abort mechanism). This typically makes the swapping
+;                      cost much lower and much less sensitive to large slot size. The worst case
+;                      swapping cost is still good (abort mechanism cost is very small).
+;                      Probably only worth supporting this on ARMs with simple instruction restart
+;                      after abort (originally StrongARM revT or later for Ursula)
+;
+; AMB_LimpidFreePool - if {TRUE}, the cache(s) can be assumed to be clear with respect to the FreePool
+;                      when AMBControl fetches pages from it. This allows AMBControl to avoid any
+;                      cache clean/flush for moving pages out of the FreePool. This assumption is
+;                      valid if either: FreePool pages are uncacheable; or FreePool pages are
+;                      never used in situ; or FreePool pages are flushed after use in situ.
+;
+; AMB_ChocTrace      - if {TRUE}, keep trace info for some enhanced code calls and data (probably development only)
+
+                    GBLL    AMB_LazyMapIn
+                    GBLL    AMB_LimpidFreePool
+                    GBLL    AMB_ChocTrace
+
+AMB_LazyMapIn       SETL    {TRUE}  :LAND: ChocolateAMB
+AMB_LimpidFreePool  SETL    {TRUE}  :LAND: ChocolateAMB   ;allowed because FreePool is currently marked uncacheable
+                                                          ;current implementation assumes uncacheability as criterion
+
+AMB_ChocTrace       SETL    {FALSE} :LAND: ChocolateAMB   ;development only
+
        END
diff --git a/s/AMBControl/Workspace b/s/AMBControl/Workspace
index bbdb7b92..0d2524b2 100644
--- a/s/AMBControl/Workspace
+++ b/s/AMBControl/Workspace
@@ -14,36 +14,76 @@
 ;
 ; > s.Workspace
 
-; task node format
-                  ^       0
-AMBNode_id        #       4     ; magic identifier
-AMBNode_handle    #       4     ; handle for external reference
-AMBNode_prev      #       4     ; -> previous node
-AMBNode_next      #       4     ; -> next node
-AMBNode_pagetable #       0     ; data comprising page table from here on
-AMBNode_Npages    #       4     ; no. of pages in page list
-AMBNode_startaddr #       4     ; logical address of first page (-1 means nowhere)
-AMBNode_PPL       #       4     ; PPL ('page protection level') for pages
-AMBNode_pages     #       0     ; list of pages from here on (1 word per page no.)
-
-
-; main workspace
-                ^       0,R12
-AMBNhandles     #       4       ; total handles available
-AMBNtasks       #       4       ; No. of tasks currently allocated
-AMBMappedInNode #       4       ; node ptr of mapped-in task, or 0 for none
-
-;ptr to node handle array (1 word per entry)
-AMBNodeHandles  #       4
-
-;ptr to physical page bin array
-AMBPhysBin         #       4
-AMBPhysBinEntries  #       4
-
-;dummy node (0 page entries) forms anchor of circular node list
-;this averts the need for any special case for add or remove node
-AMBAnchorNode   #       (AMBNode_pages - AMBNode_id)
-
-AMBmaxwork      *       :INDEX:@
+
+;
+;task node format
+;
+                   ^  0
+AMBNode_HdrStart   #  0
+AMBNode_id         #  4               ;magic identifier
+AMBNode_handle     #  4               ;handle for external reference
+AMBNode_prev       #  4               ;ptr to previous node
+AMBNode_next       #  4               ;ptr to next node
+AMBNode_pagetable  #  0               ;data comprising page table from here on
+AMBNode_Npages     #  4               ;no. of pages in page list
+AMBNode_startaddr  #  4               ;logical address of first page (-1 means nowhere)
+AMBNode_PPL        #  4               ;PPL ('page protection level') for pages
+AMBNode_pages      #  0               ;list of page numbers from here on (1 word per page)
+AMBNode_HdrEnd     #  0
+;
+AMBNode_HdrSize    *  AMBNode_HdrEnd - AMBNode_HdrStart
+
+
+;
+;main workspace
+;
+                    ^  0,R12
+AMBNhandles         #  4               ;total handles available
+AMBNtasks           #  4               ;no. of tasks currently allocated
+AMBMappedInNode     #  4               ;node ptr of mapped-in task, or 0 for none
+AMBNodeHandles      #  4               ;ptr to node handle array (1 word per entry)
+AMBPhysBin          #  4               ;ptr to physical page bin array
+AMBPhysBinEntries   #  4               ;no. of entries in physical page bin array
+AMBAnchorNode       #  AMBNode_HdrSize ;dummy node - see note (1) below
+;
+  [ ChocolateAMB
+AMBFlags            #  4               ;bits defined as below
+AMBNContextSwitches #  4               ;monotonic count of total no. of task map-in's (eg. for performance tracing)
+    [ AMB_ChocTrace
+AMBNmakeunsparse    #  4               ;count of no. of calls to AMB_MakeUnsparse
+AMBNmemmoveshrink   #  4               ;count of no. of Service_MemoryMoved shrink fixups
+AMBNmemmovegrow     #  4               ;count of no. of Service_MemoryMoved grow fixups
+    ]
+AMBMappedInNpages   #  4               ;no. of pages of MappedInNode really mapped in
+AMBMappedInRegister #  AMBMIRegWords*4 ;1 bit per page - see note (2) below
+  ]
+;
+AMBmaxwork          *  :INDEX:@        ;size of main workspace (assumed to be multiple of 4 bytes)
+
+
+  [ ChocolateAMB
+;
+;definition of bits in AMBFlags
+;
+AMBFlag_LazyMapIn_disable  * &80000000 ;bit  31    LazyMapIn permanent disable (eg. not running on StrongARM)
+AMBFlag_LazyMapIn_suspend  * &40000000 ;bit  30    LazyMapIn suspend (controlled via AMB SWI)
+                                       ;bits 29..0 reserved (0)
+;
+  ]
+
+;Notes:
+;
+; (1) AMBAnchorNode is a dummy node with 0 page entries that forms the anchor of a
+;     circular node list. This averts the need for any special case for adding or
+;     removing nodes.
+;
+; (2) AMBMappedInRegister is a 'bitmap' of the current page mapping status of the
+;     MappedInNode. This supports AMB_LazyMapIn. Bit n corresponds to the n'th page
+;     of the MappedInNode; if it is set, then that page is currently mapped in. The
+;     bits are packed 'little endian', so bit 0 is the LSB of word 0, bit 31 is
+;     the MSB of word 0, bit 32 is the LSB of word 1 and so on. The bits are only
+;     significant when AMBMappedInNpages is > 0 (and then all AMBNode_Npages bits
+;     for the MappedInNode are significant).
+
 
     END
diff --git a/s/AMBControl/allocate b/s/AMBControl/allocate
index e067c63a..432bab77 100644
--- a/s/AMBControl/allocate
+++ b/s/AMBControl/allocate
@@ -27,6 +27,8 @@
 allocate
         Push    "R0,R3,R4,LR"
 
+;  Debug AMB,"allocate ",r0,r1
+
         MOV     R3,#AbsMaxAppSize
         SUB     R3,R3,#ApplicationStart
         MOV     R3,R3,LSR #Log2PageSize   ;R3 = absolute max app pages
@@ -40,44 +42,16 @@ allocate
         CMP     R4,#0            ;any handles available?
         BNE     %FT01
 
-  [ {TRUE} ; give up
+  ; give up
         Pull    "R0,R3,R4,LR"
         ADR     R0,err_nomorehandles
         B       SLVK_SetV
-  ]
-
-  [ {FALSE} ; oh no we don't, we're not a module now
-;try to extend handles array
-        MOV     R2,R0
-        MOV     R0,#ModHandReason_ExtendBlock
-        MOV     R3,#(GrowMaxNodes:SHL:2)
-        SWI     XOS_Module
-        BVS     alloc_done
-        MOV     R0,R2
-        STR     R0,AMBNodeHandles   ;in case block has moved
-        LDR     R3,AMBNhandles
-        STR     R3,[R0]             ;first free handle now
-        ADD     LR,R3,#GrowMaxNodes
-        STR     LR,AMBNhandles
-        ADD     R4,R0,R3,LSL #2
-        ADD     R3,R3,#1
-;put new handles on free list
-00
-        STR     R3,[R4],#4
-        ADD     R3,R3,#1
-        CMP     R3,LR
-        BNE     %BT00
-        MOV     R3,#0
-        STR     R3,[R4]          ;0 = end of list
-        LDR     R4,[R0]          ;now we have a useable handle
-  ]
 
 01
 ;get memory for node - from RMA
         MOV     R3,#(AMBNode_pages - AMBNode_id) ;size excluding page list
         ADD     R3,R3,R1,LSL #2                  ;plus one word per page
-        MOV     R0,#ModHandReason_Claim
-        BL      XROS_Module
+        BL      AMB_BlockClaim
         BVS     alloc_done
 
 ;remember handle in node
@@ -128,16 +102,17 @@ alloc_ok
 
         STR     R2,AMBMappedInNode       ;allocated node is also mapped in
         LDR     R2,[R2,#AMBNode_handle]  ;change address to handle
+        CLRV
 
 alloc_done
+;  Debug AMB,"<alloc ",r1,r2
         STRVS   R0,[SP]
         Pull    "R0,R3,R4,LR"
         B       SLVK_TestV
 
 ;free page table space and return 0 handle
 alloc_zeropages
-        MOV     R0,#ModHandReason_Free
-        BL      XROS_Module
+        BL      AMB_BlockFree
         MOV     R1,#0
         MOV     R2,#0
         B       alloc_done
diff --git a/s/AMBControl/deallocate b/s/AMBControl/deallocate
index ba8caaf4..2e9b47c6 100644
--- a/s/AMBControl/deallocate
+++ b/s/AMBControl/deallocate
@@ -27,6 +27,8 @@
 deallocate
         Push    "R0-R3,LR"
 
+;  Debug AMB,"deallocate ",r0,r2
+
       [ ValidateAMBHandles
         ;validate handle
         LDR     R0,AMBNhandles
@@ -76,8 +78,8 @@ deallocate
         STREQ   R0,AMBMappedInNode
 
 ;free node (at R2)
-        MOV     R0,#ModHandReason_Free
-        BL      XROS_Module
+        BL      AMB_BlockFree
+
 dealloc_done
         STRVS   R0,[SP]
         Pull    "R0-R3,LR"
diff --git a/s/AMBControl/growp b/s/AMBControl/growp
index 88126db7..e3d47757 100644
--- a/s/AMBControl/growp
+++ b/s/AMBControl/growp
@@ -62,10 +62,21 @@ growpages ROUT
         ;       R5 := start logical address
         BL      AMB_FindMemMapEntries      ;find page nos.
 
+  [ AMB_LazyMapIn
+        LDR     R5,AMBFlags
+        TST     R5,#AMBFlag_LazyMapIn_disable :OR: AMBFlag_LazyMapIn_suspend
+        ;
+        MOVEQ   R5,#-1                     ;map the pages to Nowhere initially
+        MOVEQ   R6,#AP_Duff
+        LDRNE   R5,[R0,#AMBNode_startaddr]
+        ADDNE   R5,R5,R7,LSL #Log2PageSize ;R5 := first new page new address
+        LDRNE   R6,[R0,#AMBNode_PPL]       ;R6 := dest PPL flags
+  |
         LDR     R5,[R0,#AMBNode_startaddr]
         ADD     R5,R5,R7,LSL #Log2PageSize ;R5 := first new page new address
         LDR     R6,[R0,#AMBNode_PPL]       ;R6 := dest PPL flags
-
+  ]
+        ;
         ;entry: R3 = no. of pages, R4 -> list of page entries,
         ;       R5 = start logical address, R6 = PPL
         BL      AMB_SetMemMapEntries       ;remap
@@ -81,7 +92,8 @@ growpages ROUT
         STR     R5,[R6,#MemLimit]          ;update MemLimit
 
 02
-        STRVS   R0,[SP]
+;;;        STRVS   R0,[SP]
+        CLRV
         Pull    "R0-R7,PC"
 
   [ ShrinkableDAs
diff --git a/s/AMBControl/growshrink b/s/AMBControl/growshrink
index b28a568a..29ea8634 100644
--- a/s/AMBControl/growshrink
+++ b/s/AMBControl/growshrink
@@ -31,6 +31,8 @@ growshrink
 
         Push    "R0,R2,R4,R5,LR"
 
+;  Debug AMB,"growshrink ",r0,r1,r2
+
         MOV     R5,#AbsMaxAppSize
         SUB     R5,R5,#ApplicationStart
         MOV     R5,R5,LSR #Log2PageSize   ;R5 = absolute max app pages
@@ -102,13 +104,12 @@ gs_done
 grwshr_node
         Push    "R0,R3,R4,LR"
         CMP     R1,#0
-        BEQ     grwshrn_free       ;shrunk to nothing
-        SUB     R4,R1,R5
-        MOV     R3,R4,ASL #2
-        MOV     R4,R2              ;so we can check for moved block
-        MOV     R0,#ModHandReason_ExtendBlock
-        BL      XROS_Module
-        MOVVS   R2,R4              ;in case block ptr not preserved on error
+        BEQ     grwshrn_free                     ;shrunk to nothing
+        MOV     R3,#(AMBNode_pages - AMBNode_id) ;new size excluding page list
+        ADD     R3,R3,R1,LSL #2                  ;new size
+        MOV     R4,R2                            ;so we can check for moved block
+        BL      AMB_BlockResize
+        MOVVS   R2,R4                            ;in case block ptr not preserved on error
         BVS     grwshrn_done
 ;fix-up links if block has moved
         CMP     R4,R2
@@ -152,8 +153,7 @@ grwshrn_free
         MOVEQ   R0,#0
         STREQ   R0,AMBMappedInNode
 
-        MOV     R0,#ModHandReason_Free
-        BL      XROS_Module
+        BL      AMB_BlockFree
         MOVVC   R2,#0
         B       grwshrn_done
 
diff --git a/s/AMBControl/main b/s/AMBControl/main
index ee8ca68d..af358305 100644
--- a/s/AMBControl/main
+++ b/s/AMBControl/main
@@ -13,28 +13,36 @@
 ; limitations under the License.
 ;
 
-; AMBControl - takes care of application memory management (for Wimp)
-
-;Nov 95 - Started by mjs
+; > s.main
 
 ;;; Initialisation
 ;
 AMBControl_Init
         Push    "R0-R4,R12,LR"
 
+;claim main workspace
         LDR     R3,=AMBmaxwork
         BL      ClaimSysHeapNode
-;;;        BVS     err_cantclaim - this should not happen
+;;;     BVS     err_cantclaim - this should not happen
 
 ;don't store ws pointer till end of initialise - service routines must
 ;know when initialise is not yet complete
 ;
         MOV     R12,R2
 
-;block for handle array
+;zero-init workspace
+        MOV     R1,#0
+        LDR     R3,=AMBmaxwork
+        ADD     R3,R3,R2
+00
+        STR     R1,[R2],#4
+        CMP     R2,R3
+        BLO     %BT00
+
+;claim block for handle array
         MOV     R3,#(AMBInitialMaxNodes:SHL:2)
         BL      ClaimSysHeapNode
-;;;        BVS     err_cantclaim
+;;;     BVS     err_cantclaim
         STR     R2,AMBNodeHandles
 
 ;put all handles on free list (entry 0 is used as hdr of free list)
@@ -49,7 +57,7 @@ AMBControl_Init
         MOV     R0,#0       ; = end of list
         STR     R0,[R2]
 
-;block for PhysBin array
+;claim block for PhysBin array
         LDR     R3,=MaxCamEntry
         LDR     R3,[R3]
         ADD     R3,R3,#1                   ;no. of RAM pages extant
@@ -57,7 +65,7 @@ AMBControl_Init
         STR     R3,AMBPhysBinEntries
         MOV     R3,R3,LSL #2               ;1 word per entry
         BL      ClaimSysHeapNode
-;;;        BVS     err_cantclaim
+;;;     BVS     err_cantclaim
         STR     R2,AMBPhysBin
 
 ;init PhysBin
@@ -77,22 +85,21 @@ AMBControl_Init
         SUBS    R4,R4,#1
         BNE     %BT03
 
-; init anchor node stuff etc.
-        MOV     R0,#0
-        STR     R0,AMBNtasks
-        STR     R0,AMBMappedInNode
+;init any other workspace that shouldn't init as 0
         ADR     R1,AMBAnchorNode
-        MOV     R3,R1
-        STR     R0,[R1],#4  ; node id = 0 for ank node (not a real node!)
-        STR     R0,[R1],#4  ; handle = 0
-        STR     R3,[R1],#4  ; prev (starts -> ank node)
-        STR     R3,[R1],#4  ; next (starts -> ank node)
-        STR     R0,[R1],#4  ; Npages
-        STR     R0,[R1],#4  ; startaddr
-        STR     R0,[R1],#4  ; PPL
-
+        STR     R1,[R1,#AMBNode_prev]  ;anchor prev initially -> anchor (empty list)
+        STR     R1,[R1,#AMBNode_next]  ;anchor next initially -> anchor (empty list)
+  [ AMB_LazyMapIn
+        ; currently always disable, need to sort out when abort fix up is supported
+        ; and for which ARMs
+        ;
+        ! 0, "AMBControl currently always disables LazyMapIn (needs abort handler hooks)"
+        ;
+        MOV     R1,#AMBFlag_LazyMapIn_disable
+        STR     R1,AMBFlags
+  ]
         MOV     R0,#AMBControl_ws
-        STR     R12,[R0]           ;now initialisation is complete
+        STR     R12,[R0]               ;now initialisation is complete
 
         Pull    "R0-R4,R12,PC"
 
@@ -119,7 +126,11 @@ reasons0
         B       growshrink   ;2
         B       mapslot      ;3
         B       readinfo     ;4
+  [ AMB_LazyMapIn
+        B       laziness     ;5
+  |
         B       reserved     ;5
+  ]
         B       reserved     ;6
         B       reserved     ;7
         B       mjs_info     ;8 - system reason code, dumps info to buffer
@@ -128,6 +139,58 @@ reasons1
         B       SLVK_SetV
 
 
+  [ AMB_LazyMapIn
+;
+;entry: R0=5 (reason),R1=1 for lazy on, 0 for lazy off, -1 to read lazy only
+;exit: R1=new lazy value, after any restrictions of platform applied
+;
+;action: if reading only, if lazy disabled, or if new state = current, do nothing
+;        if state is changing, map out any current node, change state, map in any current node
+;
+laziness ROUT
+       Push    "R2-R3,LR"
+       CMP     R1,#-1
+       BEQ     %FT20
+       LDR     R2,AMBFlags                      ;R2 := current flags
+       TST     R2,#AMBFlag_LazyMapIn_disable    ;disable is permanent
+       BNE     %FT20
+       CMP     R1,#0
+       MOV     R1,R2
+       ORREQ   R1,R1,#AMBFlag_LazyMapIn_suspend
+       BICNE   R1,R1,#AMBFlag_LazyMapIn_suspend ;R1 := new flags
+       EOR     R3,R1,R2
+       TST     R3,#AMBFlag_LazyMapIn_suspend    ;is suspend status changing?
+       BEQ     %FT20
+       LDR     R3,AMBMappedInNode
+       CMP     R3,#0
+       BEQ     %FT10
+       Push    "R0-R3"
+       MOV     R0,#3
+       MOV     R1,#-1
+       LDR     R2,[R3,#AMBNode_handle]
+       SWI     XOS_AMBControl                   ;map out current node
+       Pull    "R0-R3"
+10
+       STR     R1,AMBFlags
+       CMP     R3,#0
+       BEQ     %FT20
+       Push    "R0-R3"
+       MOV     R0,#3
+       MOV     R1,#0
+       LDR     R2,[R3,#AMBNode_handle]
+       SWI     XOS_AMBControl                   ;map in current node
+       Pull    "R0-R3"
+20
+       LDR     R1,AMBFlags
+       TST     R1,#AMBFlag_LazyMapIn_disable :OR: AMBFlag_LazyMapIn_suspend
+       MOVEQ   R1,#1
+       MOVNE   R1,#0
+       Pull    "R2-R3,LR"
+       B       SLVK
+;
+  ] ;AMB_LazyMapIn
+
+
 ;entry: R0=8 (reason),R1 -> buffer (say 4k for up to 255 tasks)
 ;exit: buffer filled:
 ;       0   Ntasks
@@ -171,11 +234,6 @@ reserved
 
 ;;; errors (sod internationalisation)
 
-;;;err_cantclaim
-;;;        DCD     0
-;;;        DCB     "AMBControl failed to claim workspace",0
-;;;        ALIGN
-
 err_badreason
         DCD     0
         DCB     "bad AMBControl reason code",0
diff --git a/s/AMBControl/mapslot b/s/AMBControl/mapslot
index 7e816894..509b6743 100644
--- a/s/AMBControl/mapslot
+++ b/s/AMBControl/mapslot
@@ -23,8 +23,14 @@
 ;     R2 = handle
 ;     R3,R4 used if bit 8 set - see mapsome
 ;
+; Note that if bit 8 is clear, the use is restricted to mapping in or out of
+; whole slots only. Hence if bit 8 is clear, behaviour is undefined unless
+; R1 is one of: 0, &8000 or -1.
+;
 mapslot
 
+;  Debug AMB,"mapslot",r0,r1,r2,r3,r4
+
         TST     R0,#&100   ;if bit 8 set, then mapsome
         BNE     mapsome
 
@@ -71,16 +77,48 @@ mapslot
         BEQ   ms_done      ;else do map only if not already mapped in, and asked to map in
 
 ms_domap
-        CMP     R5,#-1
+        CMP     R5,#-1                      ;EQ if it is a map out
         LDREQ   R6,=DuffEntry
         MOVNE   R6,#ApplicationStart
         STR     R6,[R1,#AMBNode_startaddr]
         MOVEQ   R6,#AP_Duff
         MOVNE   R6,#0
         STR     R6,[R1,#AMBNode_PPL]
+
+  [ AMB_LazyMapIn
+        LDRNE   R2,AMBNContextSwitches
+        ADDNE   R2,R2,#1
+        STRNE   R2,AMBNContextSwitches
+        LDR     R2,AMBFlags
+        TST     R2,#AMBFlag_LazyMapIn_disable :OR: AMBFlag_LazyMapIn_suspend
+        BNE     ms_cantbelazy
+        ;
+        ; - if map out, do sparse map out of whole page list then zero AMBMappedInNpages
+        ; - if map in, just zero AMBMappedInNpages (last map out will have cleared AMBMappedInRegister)
+        ;
+        MOV     R2,R5
+        CMP     R2,#-1
+        LDREQ   R3,AMBMappedInNpages
+        ADREQ   R5,AMBMappedInRegister
+        LDREQ   R6,[R1,#AMBNode_Npages]
+        ;entry: R3 = no. pages mapped in, R4 -> list of page entries,
+        ;       R5 -> bitmap of pages mapped in, R6=total no. of pages in page list
+        BLEQ    AMB_SetMemMapEntries_SparseMapOut
+        MOV     R3,#0
+        STR     R3,AMBMappedInNpages
+        MOV     R5,R2
+        B       ms_mapdone
+ms_cantbelazy
         ;entry: R3 = no. of pages, R4 -> list of page entries,
         ;       R5 := start logical address, R6 = PPL
         BL      AMB_SetMemMapEntries
+ms_mapdone
+  |
+        ;entry: R3 = no. of pages, R4 -> list of page entries,
+        ;       R5 := start logical address, R6 = PPL
+        BL      AMB_SetMemMapEntries
+  ]
+
 ;update AppSpace kernel stuff
         LDR     R2,[R1,#AMBNode_Npages]
         LDR     R3,=AppSpaceDANode
@@ -96,7 +134,8 @@ ms_domap
         STR     R3,AMBMappedInNode
 
 ms_done
-        STRVS   R0,[SP]
+;;;        STRVS   R0,[SP]
+        CLRV
         Pull    "R0-R6,LR"
         B       SLVK_TestV
 
diff --git a/s/AMBControl/memmap b/s/AMBControl/memmap
index 862e1461..40d1a4cb 100644
--- a/s/AMBControl/memmap
+++ b/s/AMBControl/memmap
@@ -15,25 +15,117 @@
 ; > s.memmap
 
 ; low level memory mapping
-
-; **************************************************************************************
 ;
-
-;convert page number in $reg to L2PT entry (physical address+protection bits),
+; ----------------------------------------------------------------------------------
+;
+;convert page number in $pnum to L2PT entry (physical address+protection bits),
 ;using PhysBin table for speed
 ;
-;entry: lr -> PhysBin table, r11 = protection bits
-;exit:  r12 corrupted
+;entry: $ptable -> PhysBin table, $pbits = protection bits
+;exit:  $temp corrupted
 ;
         MACRO
-        PageNumToL2PT $reg
-        BIC     r12,$reg,#(3:SHL:(AMBPhysBinShift-2)) ;word alignment for PhysBin lookup
-        LDR     r12,[lr,r12,LSR #(AMBPhysBinShift-2)] ;start physical address of bin
-        AND     $reg,$reg,#AMBPhysBinMask             ;no. pages into bin
-        ADD     $reg,r12,$reg,LSL #Log2PageSize    ;physical address of page
-        ORR     $reg,$reg,r11                      ;munge in protection bits
+        PageNumToL2PT $pnum,$ptable,$pbits,$temp
+        BIC     $temp,$pnum,#(3:SHL:(AMBPhysBinShift-2))       ;word alignment for PhysBin lookup
+        LDR     $temp,[$ptable,$temp,LSR #(AMBPhysBinShift-2)] ;start physical address of bin
+        AND     $pnum,$pnum,#AMBPhysBinMask                    ;no. pages into bin
+        ADD     $pnum,$temp,$pnum,LSL #Log2PageSize            ;physical address of page
+        ORR     $pnum,$pnum,$pbits                             ;munge in protection bits
         MEND
 
+
+  [ AMB_LazyMapIn
+
+; ----------------------------------------------------------------------------------
+;
+;AMB_LazyFixUp
+;
+; *Only* for ARMs where the abort handler can restart instructions
+;
+; Routine to be used in abort handlers (in abort32 mode), that checks to see if abort
+; is expected, and fixes things up if so, ready to restart instruction.
+;
+; Fix up consists of mapping in affected page, and updating AMBMappedInRegister. This
+; may seem like a lot of work, but remember that the L2PT and CAM updates for each page are
+; needed anyway in non-lazy scheme, so there is really only a housekeeping overhead.
+;
+; There is no cache clean/flush consideration here, since the map is a map in from Nowhere.
+; TLB flush consideration is left to main abort handler code - in fact there may not
+; be a TLB flush consideration at all, if ARM TLB can be assumed not to cache an
+; entry which is a translation fault, as seems rational.
+;
+; entry: r0 = aborting address (data address for data abort, instruction address
+;        for prefetch abort), r1-r7 trashable, no stack
+; exit:  r0 = non-zero if abort was expected and fixed up, zero if not
+;
+AMB_LazyFixUp ROUT
+        ; not hooked in yet!
+        ! 0, "AMB_LazyFixUp needs hooking into abort handlers"
+        MOV     r7,r12
+        MOV     r12,#AMBControl_ws
+        LDR     r12,[r12]
+        CMP     r12,#0
+        BEQ     %FT20
+        SUBS    r0,r0,#ApplicationStart
+        BMI     %FT20
+        MOV     r0,r0,LSR #Log2PageSize                  ;address now in terms of pages from ApplicationStart
+        LDR     r1,AMBMappedInNode
+        CMP     r1,#0
+        BEQ     %FT20
+        LDR     r2,[r1,#AMBNode_Npages]
+        CMP     r2,r0
+        BLS     %FT20
+;
+;need not check MappedInRegister first, since if abort has happened in range of current
+;AppSpace, then the page can be assumed to be mapped out
+;
+        ADD     r1,r1,#AMBNode_pages
+        ADD     r1,r1,r0,LSL #2                          ;r1 -> page involved, in node page list
+        LDR     r2,AMBPhysBin
+        ! 0, "AMB_LazyFixup a symbol for L2PT protection bits would be handy"
+        MOV     r3,#&FF0
+        ORR     r3,r3,#&E                                ;&FFE = L2PT protection bits for ordinary page
+        LDR     r4,[r1]
+        MOV     r6,r4
+        PageNumToL2PT r4,r2,r3,r5
+;
+;here, r6 = page number of page involved, r4 = new L2PT entry value to map in page
+;
+        LDR     r2,AMBMappedInNpages                     ;for convenience, update bitmap etc. here...
+        ADD     r2,r2,#1
+        STR     r2,AMBMappedInNpages
+        ADR     r2,AMBMappedInRegister
+        ADD     r2,r2,r0,LSR #5-2                        ;r2 -> bitmap word affected
+        BIC     r2,r2,#3
+        AND     r3,r0,#31
+        MOV     r5,#1
+        MOV     r5,r5,LSL r3                             ;mask for bit affected in bitmap word
+        LDR     r3,[r2]
+        ORR     r3,r3,r5
+        STR     r3,[r2]
+
+        ADD     r0,r0,#ApplicationStart:SHR:Log2PageSize ;address now in terms of pages from 0
+        MOV     r5,#L2PT
+        STR     r4,[r5,r0,LSL #2]                        ;update L2PT
+
+        MOV     r5,#0
+        LDR     r5,[r5,#CamEntriesPointer]
+        ADD     r5,r5,r6,LSL #3                          ;r5 -> CAM entry affected
+        MOV     r0,r0,LSL #Log2PageSize                  ;address is now ordinary again, and must be non-zero
+        MOV     r1,#0                                    ;0 = AP for ordinary page
+        STMIA   r5,{r0,r1}                               ;update CAM entry
+        MOV     r12,r7
+        MOV     pc,lr                                    ;r0 is non-zero
+20
+        MOV     r0,#0
+        MOV     r12,r7
+        MOV     pc,lr
+
+  ] ;AMB_LazyMapIn
+
+
+; ----------------------------------------------------------------------------------
+;
 ;AMB_movepagesin_L2PT
 ;
 ;updates L2PT for new logical page positions, does not update CAM
@@ -54,16 +146,16 @@ AMB_movepagesin_L2PT ROUT
         CMP     r8,#8
         BLT     %FT20
 10
-        LDMIA   r10!,{r0-r7}   ;next 8 page numbers
-        PageNumToL2PT r0
-        PageNumToL2PT r1
-        PageNumToL2PT r2
-        PageNumToL2PT r3
-        PageNumToL2PT r4
-        PageNumToL2PT r5
-        PageNumToL2PT r6
-        PageNumToL2PT r7
-        STMIA   r9!,{r0-r7}    ;write 8 L2PT entries
+        LDMIA   r10!,{r0-r7}         ;next 8 page numbers
+        PageNumToL2PT r0,lr,r11,r12
+        PageNumToL2PT r1,lr,r11,r12
+        PageNumToL2PT r2,lr,r11,r12
+        PageNumToL2PT r3,lr,r11,r12
+        PageNumToL2PT r4,lr,r11,r12
+        PageNumToL2PT r5,lr,r11,r12
+        PageNumToL2PT r6,lr,r11,r12
+        PageNumToL2PT r7,lr,r11,r12
+        STMIA   r9!,{r0-r7}          ;write 8 L2PT entries
         SUB     r8,r8,#8
         CMP     r8,#8
         BGE     %BT10
@@ -72,17 +164,15 @@ AMB_movepagesin_L2PT ROUT
         BEQ     %FT35
 30
         LDR     r0,[r10],#4
-        PageNumToL2PT r0
+        PageNumToL2PT r0,lr,r11,r12
         STR     r0,[r9],#4
         SUBS    r8,r8,#1
         BNE     %BT30
 35
-        ARM_read_ID r0
-        AND     r0,r0,#&F000
-        CMP     r0,#&A000
-        ARMA_drain_WB EQ         ;because L2PT area for AppSpace will be bufferable
         Pull    "r0-r10,r12,pc"
 
+; ----------------------------------------------------------------------------------
+;
 ;update CAM entry for page number in $reg
 ;
 ;entry: r11 -> CAM, r9 = logical addr of page, lr = PPL of page
@@ -94,6 +184,8 @@ AMB_movepagesin_L2PT ROUT
         STMIA   $reg,{r9,lr}            ;store logical addr,PPL
         MEND
 
+; ----------------------------------------------------------------------------------
+;
 ;AMB_movepagesin_CAM
 ;
 ;updates CAM, does not update L2PT
@@ -147,7 +239,8 @@ AMB_movepagesin_CAM ROUT
         BNE     %BT30
         Pull    "r0-r11,pc"
 
-
+; ----------------------------------------------------------------------------------
+;
 ;AMB_movepagesout_CAM
 ;
 ;updates CAM, does not update L2PT
@@ -190,7 +283,8 @@ AMB_movepagesout_CAM ROUT
         BNE     %BT30
         Pull    "r0-r11,pc"
 
-
+; ----------------------------------------------------------------------------------
+;
 ;AMB_movepagesout_L2PT
 ;
 ;updates L2PT for old logical page positions, does not update CAM
@@ -229,40 +323,10 @@ AMB_movepagesout_L2PT ROUT
         SUBS    r8,r8,#1
         BNE     %BT30
 35
-        ARM_read_ID r0
-        AND     r0,r0,#&F000
-        CMP     r0,#&A000
-        ARMA_drain_WB EQ         ;because L2PT area for AppSpace will be bufferable
         Pull    "r0-r8,pc"
 
-  [ ARM810support
-    ;Previously supported ARMs all tolerate cache (clean and) flush _after_
-    ;remapping - ARMs 6,7 because there is no clean, StrongARM because the cache
-    ;writebacks use physical address.
-    ;ARM810 does not support clean of writeback cache after remapping, since
-    ;writebacks use virtual address. Rather than completely restructure code,
-    ;this routine is called before remapping where necessary, and cleans/flushes
-    ;if it finds we are running on ARM 810.
-    ;
-    ;corrupts r3
-    ;
-AMB_cachecleanflush_ifARM810
-        ARM_read_ID r3
-        AND     r3,r3,#&F000
-        CMP     r3,#&8000
-        MOVNE   pc,lr           ;not ARM8
-    [ ARM810cleanflushbroken
-        Push    "lr"
-        ARM8_cleanflush_IDC r3,lr
-        Pull    "pc"
-    |
-        ARM8_cleanflush_IDC r3
-        MOV     pc,lr
-    ]
-
-  ] ;ARM810support
-
-;**************************************************************************
+; ----------------------------------------------------------------------------------
+;
 ; AMB_SetMemMapEntries:
 ;
 ; entry:
@@ -271,9 +335,8 @@ AMB_cachecleanflush_ifARM810
 ;   R5 =  start logical address of mapping (-1 means 'out of the way')
 ;   R6 =  PPL ('page protection level') for mapping
 ;
-; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
 AMB_SetMemMapEntries ROUT
+
         Push    "r0-r4,r7-r11,lr"
 
         MOVS    r8,r3
@@ -298,8 +361,13 @@ AMB_SetMemMapEntries ROUT
         LDR     r2,[r10]                    ;page number of 1st page
         MOV     r7,#0
         LDR     r7,[r7,#CamEntriesPointer]  ;r7 -> CAM
-        ADD     r1,r7,r2,LSL #3
+        ADD     r1,r7,r2,LSL #3             ;r1 -> CAM entry for 1st page
+  [ AMB_LimpidFreePool
+        LDR     r4,[r1]                     ;fetch old logical addr. of 1st page from CAM
+        LDR     r3,[r1,#4]                  ;fetch old PPL of 1st page from CAM
+  |
         LDR     r4,[r1]                     ;fetch old logical addr. of 1st page from CAM
+  ]
 
         CMP     r5,#-1
         BEQ     AMB_smme_mapout
@@ -309,135 +377,199 @@ AMB_SetMemMapEntries ROUT
         BEQ     AMB_smme_mapin
 
 ;map from somewhere to somewhere (should be App Space <-> Free Pool)
-;could be an optimise here if source is FreePool and we know that FreePool
-;has not been used - ie. no need to clean/flush cache(s) - not done yet (requires
-;sorting of Wimp_ClaimFreeMemory)
-  [ ARM810support
-        BL      AMB_cachecleanflush_ifARM810
+;
+  [ AMB_LimpidFreePool
+    ;can avoid cache clean/flush for moving pages out from FreePool, since FreePool pages are uncacheable
+    ;
+        TST     r3, #DynAreaFlags_NotCacheable  ;test PPL of 1st page for not cacheable bit set
+        BEQ     AMB_smme_mapnotlimpid           ;if clear, must do full map somewhere with cache clean/flush
+    ;
+    ;this should be map FreePool -> App Space then
+    ;
+        MOV     r0,r4                            ;address of 1st page
+        MOV     r1,r8                            ;number of pages
+        MOV     r3,#0
+        ARMop   MMU_ChangingUncachedEntries,,,r3 ;no cache worries, hoorah
+        MOV     r3,r5
+        BL      AMB_movepagesout_L2PT            ;unmap 'em from where they are
+        BL      AMB_movepagesin_L2PT             ;map 'em to where they now be
+        BL      AMB_movepagesin_CAM              ;keep the bloomin' soft CAM up to date
+        Pull    "r0-r4,r7-r11, pc"
+AMB_smme_mapnotlimpid
   ]
+;
+        MOV     r0,r4                            ;address of 1st page
+        MOV     r1,r8                            ;number of pages
+        MOV     r3,#0
+        ARMop   MMU_ChangingEntries,,,r3         ;
         MOV     r3,r5
         BL      AMB_movepagesout_L2PT
         BL      AMB_movepagesin_L2PT
         BL      AMB_movepagesin_CAM
-        B       AMB_smme_cachecleanflush ;needed because of the map out from source
+        Pull    "r0-r4,r7-r11, pc"
 
-;all pages sourced from same old logical page 'nowhere'
+;all pages sourced from same old logical page Nowhere, ie. pages currently mapped out, no cache worries
+;
 AMB_smme_mapin
+        MOV     r0,r4                            ;address of 1st page
+        MOV     r1,r8                            ;number of pages
+        MOV     r3,#0
+        ARMop   MMU_ChangingUncachedEntries,,,r3 ;TLB coherency, possibly not needed (TLBs shouldn't cache 0 entries)
         MOV     r3,r5
         BL      AMB_movepagesin_L2PT
         BL      AMB_movepagesin_CAM
-;don't need to flush cache at end of mapin (already coherent, since
-;nothing mapped in before), but do need to flush TLB (eg. TLB will cache
-;access denial for app space after mapout)
-        B       AMB_smme_TLBflush
+        Pull    "r0-r4,r7-r11, pc"
 
-;all pages destined for same new logical page 'nowhere'
+;all pages destined for same new logical page Nowhere, ie. mapping them out
+;
 AMB_smme_mapout
-  [ ARM810support
-        BL      AMB_cachecleanflush_ifARM810
-  ]
+        MOV     r0,r4                            ;address of 1st page
+        MOV     r1,r8                            ;number of pages
+        MOV     r3,#0
+        ARMop   MMU_ChangingEntries,,,r3         ;
         LDR     r3,=DuffEntry
         BL      AMB_movepagesout_L2PT
         BL      AMB_movepagesout_CAM
 
-;(clean and) flush cache(s) appropriately, then flush TLB(s)
-AMB_smme_cachecleanflush
-        ARM_read_ID r0
-        AND     r0,r0,#&F000
-  [ ARM810support
-        CMP     r0,#&8000      ;cache clean/flush done before remapping if ARM810
-        ARM8_flush_TLB EQ
-        Pull    "r0-r4,r7-r11, pc",EQ
-  ]
-        CMP     r0,#&A000
-        BEQ     AMB_smme_cachecleanflush_strongarm
-
-        MOV     r11, #0
-        ARMop   MMU_Changing,,,r11
+AMB_smme_exit
         Pull    "r0-r4,r7-r11, pc"
 
-AMB_smme_cachecleanflush_strongarm
 
-;we have a StrongARM then
+
+  [ AMB_LazyMapIn
+
+; ----------------------------------------------------------------------------------
 ;
-;here, r4 = old logical addr. of 1st page, r8 = no. of pages
+; AMB_SetMemMapEntries_SparseMapOut:
 ;
-;StrongARM lets us clean data cache (DC) after remapping, because it writes back by
-;physical address.
 ;
-        MOV     r0,r4                      ;r0 := start address for clean/flush
-        ADD     r1,r0,r8,LSL #Log2PageSize ;r1 := end address for clean/flush (exclusive)
+; entry:
+;   R3  =  no. of pages currently mapped in (0=none)
+;   R4  -> list of page entries (1 word per entry, giving page no.)
+;   R5  -> bitmap of pages mapped in (1 bit per page in whole page list)
+;   R6  =  total no. of pages in slot
+;
+AMB_SetMemMapEntries_SparseMapOut ROUT
 
-;Cleaning a sufficiently small space by range will be quicker, because of the fixed
-;memory reading cost for a full DC clean. A sufficiently large space will be better handled
-;by full clean, because of the huge number of clean/flush line instructions for the range
-;case. We use a threshold to switch between the two schemes. The value of the threshold
-;depends on memory speed, core speed etc. but is not particularly critical.
+        CMP     r3,#0
+        MOVEQ   pc,lr
+        Push    "r0-r11,lr"
 
-        SUB     r2,r1,r0
-        CMP     r2,#AMB_ARMA_CleanRange_thresh
-        BLO     AMB_smme_StrongARM_flushrange
+        MOV     r10,r4                            ;ptr to page list
+        MOV     r7,#0
+        LDR     r7,[r7,#CamEntriesPointer]        ;r7 -> CAM
+        LDR     lr,=L2PT                          ;lr -> L2PT
+        MOV     r9,#AP_Duff                       ;permissions for DuffEntry
+        LDR     r1,=DuffEntry                     ;means Nowhere, in CAM
+        MOV     r4,#ApplicationStart              ;log. address of first page
+        MOV     r2,#0                             ;r2 is zero during sparse map out
+
+        ;if the number of pages mapped in is small enough, we'll do cache/TLB coherency on
+        ;just those pages, else global (performance decision, threshold probably not critical)
+
+        ARMop   Cache_RangeThreshold,,,r2         ;returns threshold (bytes) in r0
+        CMP     r3,r0,LSR #Log2PageSize
+        MOVLO   r6,#0                             ;r6 := 0 if we are to do coherency as we go
+        BLO     %FT10                             ;let's do it
+
+        Push    "lr"                              ;global coherency
+        ARMop   MMU_Changing,,,r2
+        Pull    "lr"
+        B       %FT10
+
+;skip next 32 pages then continue
+06
+        ADD     r10,r10,#32*4
+        ADD     r4,r4,#32*PageSize
+
+;find the sparsely mapped pages, map them out, doing coherency as we go if enabled
+10
+        MOV     r8,#1                             ;initial bitmap mask for new bitmap word
+        LDR     r11,[r5],#4                       ;next word of bitmap
+        CMP     r11,#0                            ;if next 32 bits of bitmap clear, skip
+        BEQ     %BT06                             ;skip loop must terminate if r3 > 0
+12
+        TST     r11,r8                            ;page is currently mapped in if bit set
+        BEQ     %FT16
+        TEQ     r6, #0
+        BNE     %FT14                             ;check for coherency as we go
+        Push    "lr"
+        MOV     r0,r4                             ;address of page
+        ARMop   MMU_ChangingEntry,,,r2
+        Pull    "lr"
+14
+        LDR     r0,[r10]                          ;page no.
+        ADD     r0,r7,r0,LSL #3                   ;r0 -> CAM entry for page
+        STMIA   r0,{r1,r9}                        ;CAM entry for page set to DuffEntry,AP_Duff
+        STR     r2,[lr,r4,LSR #(Log2PageSize-2)]  ;L2PT entry for page set to 0 (means translation fault)
+        SUBS    r3,r3,#1
+        STREQ   r2,[r5,#-4]                       ;make sure we clear last word of bitmap, and...
+        BEQ     %FT20                             ;done
+16
+        ADD     r10,r10,#4                        ;next page no.
+        ADD     r4,r4,#PageSize                   ;next logical address
+        MOVS    r8,r8,LSL #1                      ;if 32 bits processed...
+        BNE     %BT12
+        STR     r2,[r5,#-4]                       ;zero word of bitmap we've just traversed (r2 is 0)
+        B       %BT10
 
-        MOV     r2,#ARMA_Cleaner_flipflop
-        LDR     r1,[r2]
-        EOR     r1,r1,#16*1024
-        STR     r1,[r2]
-        ARMA_clean_DC r1,r2,r3     ;effectively, fully clean/flush wrt non-interrupt stuff
-        ARMA_drain_WB
-        ARMA_flush_IC WithoutNOPs  ;do *not* flush DC - may be interrupt stuff in it
-        MOV     r0,r0              ;NOPs to ensure 4 instructions after IC flush before return
-        MOV     r0,r0
-        ARMA_flush_TLBs
-        Pull    "r0-r4,r7-r11, pc"
+20
+        Pull    "r0-r11,pc"
 
-AMB_smme_StrongARM_flushrange
-
-  [ SAcleanflushbroken                  ; ARMA_cleanflush_DCentry instruction seems to be ineffective.
-01
-        ARMA_clean_DCentry r0
-        ARMA_flush_DCentry r0
-        ADD     r0,r0,#32
-        ARMA_clean_DCentry r0
-        ARMA_flush_DCentry r0
-        ADD     r0,r0,#32
-        ARMA_clean_DCentry r0
-        ARMA_flush_DCentry r0
-        ADD     r0,r0,#32
-        ARMA_clean_DCentry r0
-        ARMA_flush_DCentry r0
-        ADD     r0,r0,#32
-        CMP     r0,r1
-        BLO     %BT01                   ;loop to clean DC over logical range
-  |
-01
-        ARMA_cleanflush_DCentry r0
-        ADD     r0,r0,#32
-        ARMA_cleanflush_DCentry r0
-        ADD     r0,r0,#32
-        ARMA_cleanflush_DCentry r0
-        ADD     r0,r0,#32
-        ARMA_cleanflush_DCentry r0
-        ADD     r0,r0,#32
-        CMP     r0,r1
-        BLO     %BT01                   ;loop to clean DC over logical range
-  ]
 
-        ARMA_drain_WB
-        ARMA_flush_IC WithoutNOPs
-        MOV     r0,r0                   ;NOPs to ensure 4 instructions after IC flush before return
-        MOV     r0,r0
-        ARMA_flush_TLBs
 
-        Pull    "r0-r4,r7-r11, pc"
+; ----------------------------------------------------------------------------------
+;
+; AMB_MakeUnsparse
+;
+; entry: r0 = size of area (at top of current slot) to ensure is not sparsely mapped
+;
+; action: walk over space involved, to force abort handler fix up to map in any
+;         pages not already there
+;
+AMB_MakeUnsparse ROUT
+        Push    "r0-r2,r12,lr"
+;  Debug AMB,"AMB_MakeUnsparse r0",r0
+        ADD     r0,r0,#PageSize
+        SUB     r0,r0,#1
+        MOVS    r0,r0,LSR #Log2PageSize
+        BEQ     %FT20
+        MOV     r12,#AMBControl_ws
+        LDR     r12,[r12]
+        CMP     r12,#0
+        BEQ     %FT20
+        LDR     r1,AMBMappedInNode
+        CMP     r1,#0
+        BEQ     %FT20
+        LDR     r2,AMBFlags
+        TST     r2,#AMBFlag_LazyMapIn_disable :OR: AMBFlag_LazyMapIn_suspend
+        BNE     %FT20
+  [ AMB_ChocTrace
+        LDR     r2,AMBNmakeunsparse
+        ADD     r2,r2,#1
+        STR     r2,AMBNmakeunsparse
+  ]
+        LDR     r2,[r1,#AMBNode_Npages]
+; Debug AMB,"AMB_MakeUnsparse pages Npages ",r0,r2
+        CMP     r0,r2
+        MOVHI   r0,r2
+        SUB     lr,r2,r0
+        MOV     lr,lr,LSL #Log2PageSize
+        ADD     lr,lr,#ApplicationStart
+;  Debug AMB,"AMB_MakeUnsparse MappedInNode addr pages ",r1,lr,r0
+10
+        LDR     r2,[lr]                ;tends to wash data cache a bit, but this should be called rarely
+        ADD     lr,lr,#PageSize
+        SUBS    r0,r0,#1
+        BNE     %BT10
+20
+        Pull    "r0-r2,r12,pc"
 
-AMB_smme_TLBflush
-        MOV     r11,#0
-        ARMop   TLB_InvalidateAll,,,r11
-AMB_smme_exit
-        Pull    "r0-r4,r7-r11, pc"
 
+  ] ;AMB_LazyMapIn
 
-; ************************************************************************
+; ----------------------------------------------------------------------------------
+;
 ; AMB_FindMemMapEntries
 ;
 ; finds page numbers for pages currently at given logical start address,
@@ -452,8 +584,6 @@ AMB_smme_exit
 ; exit:
 ;   buffer at R4 filled in with page numbers
 ;
-; ************************************************************************
-
 AMB_FindMemMapEntries ROUT
 
         Push    "r0-r11,lr"
@@ -497,6 +627,8 @@ AMB_FindMemMapEntries ROUT
         BNE     %BT30
         Pull    "r0-r11,pc"
 
+; ----------------------------------------------------------------------------------
+;
 ;AMB_r11topagenum
 ;entry:
 ;     r0,r1,r2 = lowest addr,highest addr +1,first page no.
diff --git a/s/AMBControl/service b/s/AMBControl/service
index bac767a3..d5118c08 100644
--- a/s/AMBControl/service
+++ b/s/AMBControl/service
@@ -21,22 +21,23 @@
 ;
 ;  if there is a mapped-in node then recheck which and how many pages it owns
 ;
-;  I believe it should only be necessary to
+;  it is only necessary to:
 ;    1) reset node's idea of Npages to agree with no. of pages in app space
-;    2) find the page numbers for new pages, if Npages has increased
-;  ie. I believe it is not necessary to recheck page numbers for whole node
+;    2) if Npages has increased, find the page numbers for new pages [and update
+;       the mapped in list, if LazyMapIn]
+;  ie. page numbers of existing pages are not messed with
 ;
-AMBsrv_memorymoved
+AMBsrv_memorymoved ROUT
         Push   "R3-R6,R12,LR"
 
         MOV     R12,#AMBControl_ws
         LDR     R12,[R12]
         CMP     R12,#0
-        Pull    "R3-R6,R12,PC",EQ          ;AMBControl not initialised yet!
+        Pull    "R3-R6,R12,PC",EQ,^        ;AMBControl not initialised yet!
 
         LDR     R4,AMBMappedInNode
         CMP     R4,#0
-        Pull    "R3-R6,R12,PC",EQ          ;done if nothing mapped in
+        Pull    "R3-R6,R12,PC",EQ,^        ;done if nothing mapped in
 
         LDR     R3,[R4,#AMBNode_Npages]
 
@@ -47,7 +48,12 @@ AMBsrv_memorymoved
 
         CMP     R6,R3
         STRNE   R6,[R4,#AMBNode_Npages]    ;update Npages
-        Pull    "R3-R6,R12,PC",LE          ;done if Npages same, or shrink
+  [ AMB_LazyMapIn
+        Pull    "R3-R6,R12,PC",EQ,^        ;done if Npages same
+        BLT     %FT22                      ;shrink
+  |
+        Pull    "R3-R6,R12,PC",LE,^        ;done if Npages same, or shrink
+  ]
 
         MOV     R5,#ApplicationStart
         ADD     R5,R5,R3,LSL #Log2PageSize ;first logical address to find
@@ -55,7 +61,105 @@ AMBsrv_memorymoved
         ADD     R4,R4,R3,LSL #2            ;first page number word to use
         SUB     R3,R6,R3                   ;no. of pages to find (grow number)
         BL      AMB_FindMemMapEntries
-        Pull    "R3-R6,R12,PC"
+
+  [ AMB_LazyMapIn
+        ;if Npages has grown, update AMBMappedInNpages and set bits in bitmap for
+        ;new pages, since these will be mapped in.
+        ;
+;  Debug AMB,"AMBsrv +Npages ",R3
+    [ AMB_ChocTrace
+        LDR     R5,AMBNmemmovegrow
+        ADD     R5,R5,#1
+        STR     R5,AMBNmemmovegrow
+    ]
+        LDR     R5,AMBFlags
+        TST     R5,#AMBFlag_LazyMapIn_disable :OR AMBFlag_LazyMapIn_suspend
+        BNE     %FT21
+        LDR     R5,AMBMappedInNpages
+        ADD     R5,R5,R3
+        STR     R5,AMBMappedInNpages
+        LDR     R4,AMBMappedInNode
+        LDR     R5,[R4,#AMBNode_Npages]
+        SUB     R5,R5,R3
+        ADR     R6,AMBMappedInRegister
+        ADD     R6,R6,R5,LSR #5-2        ;first word of bitmap affected
+        BIC     R6,R6,#3
+        AND     R5,R5,#31                ;first bit of word
+        MOV     R4,#1
+        MOV     R5,R4,LSL R5             ;bitmap mask
+        LDR     R4,[R6],#4
+10
+        ORR     R4,R4,R5
+        SUBS    R3,R3,#1
+        STREQ   R4,[R6,#-4]
+        BEQ     %FT20
+        MOVS    R5,R5,LSL #1
+        BNE     %BT10
+        STR     R4,[R6,#-4]
+        MOV     R4,#-1
+12
+        CMP     R3,#32
+        BLT     %FT14
+        STR     R4,[R6],#4
+        SUBS    R3,R3,#32
+        BEQ     %FT20
+        B       %BT12
+14
+        MOV     R5,#1
+        LDR     R4,[R6],#4
+        B       %BT10
+20
+21
+        Pull    "R3-R6,R12,PC",,^
+
+22
+        SUB     R3,R3,R6                 ;no. of pages removed from app space (known unsparse before removal)
+;  Debug AMB,"AMBsrv -Npages ",R3
+    [ AMB_ChocTrace
+        LDR     R5,AMBNmemmoveshrink
+        ADD     R5,R5,#1
+        STR     R5,AMBNmemmoveshrink
+    ]
+        LDR     R5,AMBFlags
+        TST     R5,#AMBFlag_LazyMapIn_disable :OR AMBFlag_LazyMapIn_suspend
+        BNE     %FT41
+        LDR     R5,AMBMappedInNpages
+        SUB     R5,R5,R3
+        STR     R5,AMBMappedInNpages
+        LDR     R4,AMBMappedInNode
+        LDR     R5,[R4,#AMBNode_Npages]
+        ADR     R6,AMBMappedInRegister
+        ADD     R6,R6,R5,LSR #5-2        ;first word of bitmap affected
+        BIC     R6,R6,#3
+        AND     R5,R5,#31                ;first bit of word
+        MOV     R4,#1
+        MOV     R5,R4,LSL R5             ;bitmap mask
+        LDR     R4,[R6],#4
+30
+        BIC     R4,R4,R5
+        SUBS    R3,R3,#1
+        STREQ   R4,[R6,#-4]
+        BEQ     %FT40
+        MOVS    R5,R5,LSL #1
+        BNE     %BT30
+        STR     R4,[R6,#-4]
+        MOV     R4,#0
+32
+        CMP     R3,#32
+        BLT     %FT34
+        STR     R4,[R6],#4
+        SUBS    R3,R3,#32
+        BEQ     %FT40
+        B       %BT32
+34
+        MOV     R5,#1
+        LDR     R4,[R6],#4
+        B       %BT30
+40
+41
+  ] ;AMB_LazyMapIn
+
+        Pull    "R3-R6,R12,PC",,^
 
 
 ;Service_PagesSafe
@@ -65,17 +169,17 @@ AMBsrv_memorymoved
 ;
 ; action: fix-up page numbers in page lists of nodes as necessary
 ;
-AMBsrv_pagessafe
+AMBsrv_pagessafe ROUT
         Push   "R0-R1,R5-R10,R12,LR"
 
         MOV     R12,#AMBControl_ws
         LDR     R12,[R12]
         CMP     R12,#0
-        Pull   "R0-R1,R5-R10,R12,PC",EQ    ;AMBControl not initialised yet!
+        Pull   "R0-R1,R5-R10,R12,PC",EQ,^  ;AMBControl not initialised yet!
 
         LDR    R0,AMBNtasks
         CMP    R0,#0
-        Pull   "R0-R1,R5-R10,R12,PC",EQ    ;no nodes to check
+        Pull   "R0-R1,R5-R10,R12,PC",EQ,^  ;no nodes to check
 
 ;speed-up - list of pages tends to span a narrow range of page numbers, so
 ;            use min,max limits to skip search
@@ -136,7 +240,7 @@ AMBsrv_pagessafe
         LDR    R0,[R0,#AMBNode_next]
         CMP    R0,R1                 ;done if back at anchor node
         BNE    %BT01
-        Pull    "R0-R1,R5-R10,R12,PC"
+        Pull    "R0-R1,R5-R10,R12,PC",,^
 
     END
 
diff --git a/s/AMBControl/shrinkp b/s/AMBControl/shrinkp
index 52e97179..2c965c75 100644
--- a/s/AMBControl/shrinkp
+++ b/s/AMBControl/shrinkp
@@ -38,6 +38,27 @@ shrinkpages
         MOVEQ   R3,#1                   ;flag this is the mapped-in node
         MOVNE   R3,#0                   ;flag is not
 
+  [ AMB_LazyMapIn
+        ;first make sure the current mapping of mapped in node is simple,
+        ;so that main mapping can cope - easiest thing is to do a sparse map out
+        ;
+        BNE     %FT02
+        Push    "R3,R6"
+        LDR     R3,AMBFlags
+        TST     R3,#AMBFlag_LazyMapIn_disable :OR: AMBFlag_LazyMapIn_suspend
+        BNE     %FT01
+        LDR     R3,AMBMappedInNpages
+        ADD     R4,R5,#AMBNode_pages
+        LDR     R6,[R5,#AMBNode_Npages]
+        ADR     R5,AMBMappedInRegister
+        BL      AMB_SetMemMapEntries_SparseMapOut
+        MOV     R3,#0
+        STR     R3,AMBMappedInNpages
+01
+        Pull    "R3,R6"
+02
+  ]
+
         TST     R3,#1                      ;check flag
         MOVEQ   R1,#0                      ;source is not App space
         LDRNE   R1,=AppSpaceDANode         ;source is App space
@@ -73,7 +94,8 @@ shrinkpages
         STRNE   R0,[R5,#MemLimit]          ;update MemLimit
 
 02
-        STRVS   R0,[SP]
+;;;        STRVS   R0,[SP]
+        CLRV
         Pull    "R0-R7,PC"
 
 
diff --git a/s/ARMops b/s/ARMops
index 666e9683..fc697cce 100644
--- a/s/ARMops
+++ b/s/ARMops
@@ -187,6 +187,13 @@ Analyse_ARMv3
         STR     a2, [v6, #Proc_MMU_ChangingEntry]
         STR     a3, [v6, #Proc_MMU_ChangingUncached]
         STR     a4, [v6, #Proc_MMU_ChangingUncachedEntry]
+
+        ADR     a1, MMU_ChangingEntries_ARMv3
+        ADR     a2, MMU_ChangingUncachedEntries_ARMv3
+        ADR     a3, Cache_RangeThreshold_ARMv3
+        STR     a1, [v6, #Proc_MMU_ChangingEntries]
+        STR     a2, [v6, #Proc_MMU_ChangingUncachedEntries]
+        STR     a3, [v6, #Proc_Cache_RangeThreshold]
         B       %FT90
 
 Analyse_WriteThroughUnified
@@ -215,6 +222,13 @@ Analyse_WriteThroughUnified
         STR     a2, [v6, #Proc_MMU_ChangingEntry]
         STR     a3, [v6, #Proc_MMU_ChangingUncached]
         STR     a4, [v6, #Proc_MMU_ChangingUncachedEntry]
+
+        ADR     a1, MMU_ChangingEntries_Writethrough
+        ADR     a2, MMU_ChangingUncachedEntries
+        ADR     a3, Cache_RangeThreshold_Writethrough
+        STR     a1, [v6, #Proc_MMU_ChangingEntries]
+        STR     a2, [v6, #Proc_MMU_ChangingUncachedEntries]
+        STR     a3, [v6, #Proc_Cache_RangeThreshold]
         B       %FT90
 
 90
@@ -371,10 +385,37 @@ MMU_ChangingEntry_ARMv3
         MCR     p15, 0, a1, c6, c0      ; invalidate TLB entry
         MOV     pc, lr
 
+MMU_ChangingEntries_ARMv3 ROUT
+        Push    "a2"
+        MCR     p15, 0, a1, c7, c0      ; invalidate cache
+10
+        MCR     p15, 0, a1, c6, c0      ; invalidate TLB entry
+        SUBS    a2, a2, #1              ; next page
+        ADD     a1, a1, #PageSize
+        BNE     %BT10
+        Pull    "a2"
+        MOV     pc, lr
+
 MMU_ChangingUncachedEntry_ARMv3
         MCR     p15, 0, a1, c6, c0      ; invalidate TLB entry
         MOV     pc, lr
 
+MMU_ChangingUncachedEntries_ARMv3 ROUT
+        Push    "a2"
+10
+        MCR     p15, 0, a1, c6, c0      ; invalidate TLB entry
+        SUBS    a2, a2, #1              ; next page
+        ADD     a1, a1, #PageSize
+        BNE     %BT10
+        Pull    "a2"
+        MOV     pc, lr
+
+Cache_RangeThreshold_ARMv3
+        ! 0, "arbitrary Cache_RangeThreshold_ARMv3"
+        MOV     a1, #16*PageSize
+        MOV     pc, lr
+
+
 Cache_InvalidateUnified
         MOV     a1, #0
         MCR     p15, 0, a1, c7, c7
@@ -422,10 +463,36 @@ MMU_ChangingEntry_Writethrough
         Pull    "a4"
         MOV     pc, lr
 
+MMU_ChangingEntries_Writethrough  ROUT
+        Push    "a2,a4"
+        MOV     a4, #0
+        MCR     p15, 0, a4, c7, c7      ; invalidate cache
+10
+        MCR     p15, 0, a1, c8, c7, 1   ; invalidate TLB entry
+        SUBS    a2, a2, #1              ; next page
+        ADD     a1, a1, #PageSize
+        BNE     %BT10
+        Pull    "a2,a4"
+        MOV     pc, lr
+
 MMU_ChangingUncachedEntry
         MCR     p15, 0, a1, c8, c7, 1   ; invalidate TLB entry
         MOV     pc, lr
 
+MMU_ChangingUncachedEntries ROUT
+        Push    "a2"
+10
+        MCR     p15, 0, a1, c8, c7, 1   ; invalidate TLB entry
+        SUBS    a2, a2, #1              ; next page
+        ADD     a1, a1, #PageSize
+        BNE     %BT10
+        Pull    "a2"
+        MOV     pc, lr
+
+Cache_RangeThreshold_Writethrough
+        ! 0, "arbitrary Cache_RangeThreshold_Writethrough"
+        MOV     a1, #16*PageSize
+        MOV     pc, lr
 
 ;        IMPORT  Write0_Translated
 
-- 
GitLab