# file opened: mmu.asm
  1   0000              ; DOCS design (happened here, while working on it):
  2   0000              ;
  3   0000              ;     MMU <first slot number> [<last slot number>|<single slot option>], <page number>
  4   0000              ;
  5   0000              ; Maps memory page(s) to slot(s), similar to SLOT + PAGE combination, but allows to set up
  6   0000              ; whole range of consecutive slots (with consecutive memory pages). Or when only single
  7   0000              ; slot is specified, extra option can be used to extend particular slot functionality.
  8   0000              ; The slot behaviour will stay set in the current DEVICE until reset by another MMU
  9   0000              ; specifying same slot (even as part of range, that will clear the option to "default").
 10   0000              ;
 11   0000              ; Single slot option (default state is: no error/warning and no wrap = nothing special):
 12   0000              ;     e = error on writing beyond last byte of slot
 13   0000              ;     w = warning on writing beyond last byte of slot
 14   0000              ;     n = wrap address back to start of slot, map next page
 15   0000              ;
 16   0000
 17   0000                  DEVICE NONE         ; set "none" explicitly, to avoid "global device" feature
mmu.asm(18): warning: MMU is allowed only in real device emulation mode (See DEVICE)
 18   0000                  MMU                 ;; warning about non-device mode
 19   0000                  DEVICE ZXSPECTRUM128
 20   0000
 21   0000                  ;; error messages (parsing test)
mmu.asm(22): error: [MMU] First slot number parsing failed: MMU !
 22   0000                  MMU !
mmu.asm(23): error: [MMU] Second slot number parsing failed: MMU 1
 23   0000                  MMU 1
mmu.asm(24): error: [MMU] Second slot number parsing failed: MMU 1 !
 24   0000                  MMU 1 !
mmu.asm(25): warning: [MMU] Unknown slot option (legal: e, w, n): x
mmu.asm(25): error: [MMU] Comma and page number expected after slot info: MMU 1 x
 25   0000                  MMU 1 x ; white space (or comma) after char to detect it as unknown option
mmu.asm(26): warning: [MMU] Unknown slot option (legal: e, w, n): x,
mmu.asm(26): error: [MMU] Page number parsing failed: MMU 1 x,
 26   0000                  MMU 1 x,
mmu.asm(27): error: [MMU] Comma and page number expected after slot info: MMU 1 1
 27   0000                  MMU 1 1
mmu.asm(28): error: [MMU] Page number parsing failed: MMU 0,
 28   0000                  MMU 0,
mmu.asm(29): error: [MMU] Page number parsing failed: MMU 0 1,
 29   0000                  MMU 0 1,
mmu.asm(30): error: [MMU] Page number parsing failed: MMU 0 e,
 30   0000                  MMU 0 e,
mmu.asm(31): error: [MMU] Page number parsing failed: MMU 0 e,!
 31   0000                  MMU 0 e,!
 32   0000
 33   0000                  ;; correct syntax, invalid arguments
mmu.asm(34): error: [MMU] Requested page(s) must be in range 0..7
 34   0000                  MMU 0,8
mmu.asm(35): error: [MMU] Slot number(s) must be in range 0..3 (or exact starting address of slot) and form a range
 35   0000                  MMU 4,0
mmu.asm(36): error: [MMU] Slot number(s) must be in range 0..3 (or exact starting address of slot) and form a range
 36   0000                  MMU 3 4,0
mmu.asm(37): error: [MMU] Requested page(s) must be in range 0..7
 37   0000                  MMU 0 0,8
mmu.asm(38): error: [MMU] Slot number(s) must be in range 0..3 (or exact starting address of slot) and form a range
 38   0000                  MMU 1 0,0
mmu.asm(39): error: [MMU] Requested page(s) must be in range 0..7
 39   0000                  MMU 0 2,6   ; map pages 6, 7, 8 -> 8 is wrong
 40   0000
 41   0000                  ;; test functionality
 42   0000                  ; set init markers in pages 0, 5, 6 and 7
 43   0000 37 37            DB  "77"
 43   0002                ORG 0xC000
 43   C000 30 30          DB "00"
 43   C002                ORG 0xC000, 5
 43   C000 35 35          DB "55"
 43   C002                ORG 0xC000, 6
 43   C000 36 36          DB "66"
 44   C002                  PAGE 7
 44   C002                ASSERT {0xC000} == "77"
 44   C002                PAGE 6
 44   C002                ASSERT {0xC000} == "66"
 45   C002                  PAGE 5
 45   C002                ASSERT {0xC000} == "55"
 45   C002                PAGE 0
 45   C002                ASSERT {0xC000} == "00"
 46   C002
 47   C002                  ; test simple page-in
 48   C002                  MMU 0, 5
 48   C002                ASSERT {0} == "55"
 49   C002                  MMU 1 3, 5
 49   C002                ASSERT {0x4000} == "55"
 49   C002                ASSERT {0x8000} == "66"
 49   C002                ASSERT {0xC000} == "77"
 50   C002
 51   C002                  ;; test slot options (these are confined to single slot only, not to range)
 52   C002                  ; error option (guarding machine code write outside of current slot)
 53   C002                  MMU 1 e, 5
 53   C002                ASSERT {0x4000} == "55"
 54   C002                  ORG 0x7FFF
mmu.asm(54): error: Write outside of memory slot: 32768
 54   7FFF 36 73          ld (hl),'s'   ; should be error, 2B opcode leaving slot memory
 55   8001                  ASSERT {0x8000} == "6s"     ; but damage is done in the virtual memory, that's how it is
 56   8001                  ; while escaping from slot through ORG should be legal
 57   8001                  ORG 0x7FFF
 57   7FFF 00             nop
 57   8000                ORG 0x8000
 57   8000 36 36          DB "66"
 58   8002                  ; changing page within tainted slot will keep the guarding ON
 59   8002                  SLOT 1
 59   8002                PAGE 6
 59   8002                ASSERT {0x4000} == "66"           ; map page 6 also into slot 1
 60   8002                  ORG 0x7FFF
mmu.asm(60): error: Write outside of memory slot: 32768
 60   7FFF 36 73          ld (hl),'s'
 60   8001                ASSERT {0x8000} == "6s" ; error + damage check
 61   8001
 62   8001                  ; verify clearing option by another MMU
 63   8001                  MMU 1, 5
 63   8001                ASSERT {0x4000} == "55"
 64   8001                  ORG 0x7FFF
 64   7FFF 36 36          ld (hl),'6'
 64   8001                ASSERT {0x8000} == "66" ; no error
 65   8001
 66   8001                  ; warning option (guarding machine code write outside of current slot)
 67   8001                  MMU 1 w, 5
 67   8001                ASSERT {0x4000} == "55"
 68   8001                  ORG 0x7FFF
mmu.asm(68): warning: Write outside of memory slot
 68   7FFF 36 73          ld (hl),'s'   ; should be warning, 2B opcode leaving slot memory
 69   8001                  ASSERT {0x8000} == "6s"     ; but damage is done in the virtual memory, that's how it is
 70   8001                  ; while escaping from slot through ORG should be legal
 71   8001                  ORG 0x7FFF
 71   7FFF 00             nop
 71   8000                ORG 0x8000
 71   8000 36 36          DB "66"
 72   8002                  ; changing page within tainted slot will keep the guarding ON
 73   8002                  SLOT 1
 73   8002                PAGE 6
 73   8002                ASSERT {0x4000} == "66"           ; map page 6 also into slot 1
 74   8002                  ORG 0x7FFF
mmu.asm(74): warning: Write outside of memory slot
 74   7FFF 36 73          ld (hl),'s'
 74   8001                ASSERT {0x8000} == "6s" ; warning + damage check
 75   8001
 76   8001                  ; verify clearing option by another MMU when the slot is part of range
 77   8001                  MMU 0 2, 5
 77   8001                ASSERT {0x4000} == "6s"
 78   8001                  ORG 0x7FFF
 78   7FFF 36 37          ld (hl),'7'
 78   8001                ASSERT {0x8000} == "77" ; no warning
 79   8001
 80   8001                  ; next option making the memory wrap, automatically mapping in next page
 81   8001                  MMU 1 n, 2
 82   8001                  ORG 0x4000
 82   4000 6E 6E 6E...    BLOCK 3*16384, 'n' ; fill pages 2, 3 and 4 with 'n'
 83   4000                  ASSERT {0x4000} == "55" && {0x8000} == "77" ; page 5 is mapped in after that block
 84   4000                  SLOT 1                      ; verify the block write
 85   4000                  PAGE 2
 85   4000                ASSERT {0x4000} == "nn"
 86   4000                  PAGE 3
 86   4000                ASSERT {0x4000} == "nn"
 87   4000                  PAGE 4
 87   4000                ASSERT {0x4000} == "nn"
 88   4000
 89   4000                  ; do the wrap-around test with instructions, watch labels land into different pages
 90   4000                  MMU 1 n, 4
 91   4000                  ORG 0x7FFE
 92   7FFE 37           label0_p4:  scf
 93   7FFF 37           label1_p4:  scf
 94   4000 35 35        label2_p5:  db "55"     ; "55"      ; first two bytes of page 5
 95   4002 73 73 73...      BLOCK   16381, 's'  ; leaves last byte of page 5 unfilled
 96   7FFF 31 36 36     label3_p5:  ld sp,"66"  ; '166'     ; last byte of page 5, first two bytes of page 6
 97   4002                  ASSERT $ == 0x4002 && $$ == 6
 98   4002                  PAGE 4
 98   4002                ASSERT {0x7FFE} == "77"
 99   4002                  PAGE 5
 99   4002                ASSERT {0x4000} == "55" && {0x4002} == "ss" && {0x7FFE} == "1s"
100   4002                  PAGE 6
100   4002                ASSERT {0x4000} == "66"
101   4002
102   4002                  LABELSLIST "mmu.lbl"
103   4002
104   4002              ;-----------------------------------------------------------
105   4002              ; new part to test the optional third <address> argument
106   4002                  ; syntax errors
mmu.asm(107): error: [MMU] address parsing failed: MMU 0 e,0,
107   4002                  MMU 0 e,0,
mmu.asm(108): error: [MMU] address parsing failed: MMU 0 e,0,!
108   4002                  MMU 0 e,0,!
mmu.asm(109): error: Unexpected: ,
109   4002                  MMU 0 e,0,0,
110   0000
111   0000                  ; valid syntax with address -exercise different code-paths
112   0000                  ORG 0x1234
mmu.asm(113): warning: [MMU] Requested ORG address 0x4000 is out of range 0x0000..0x3FFF
113   1234                  MMU 0, 0, 0x4000
114   4000                  ASSERT 0x4000 == $ && 6 == $$ && {0x0000} == "00" && {$} == "66"
mmu.asm(115): warning: value 0x12345 is truncated to 16bit value: 0x2345
115   4000                  MMU 0, 5, 0x12345   ; warning about truncating the address
116   2345                  ASSERT 0x2345 == $ && 5 == $$
117   2345                  DISP 0x8765
mmu.asm(118): warning[displacedorg]: ORG-address set inside displaced block, the physical address is not modified, only displacement address
118   8765                  MMU 0, 7, 0x1234
119   1234                  ASSERT 0x1234 == $ && 7 ==  $$
120   1234                  MMU 0, 6, 0x3456    ; displacedorg-ok - suppress warning about ORG inside DISP
121   3456                  ASSERT 0x3456 == $ && 6 ==  $$
122   3456                  ENT
123   2345                  ASSERT 0x2345 == $ && 6 ==  $$
124   2345
125   2345              ;-----------------------------------------------------------
126   2345              ; new part to verify bugfix for #245
127   2345
128   2345                  ; error option (guarding machine code write outside of current slot)
129   2345                  MMU 1 e, 5
129   2345                ASSERT {0x4000} == "55"
130   2345                  ORG 0x7FFF
130   7FFF 3F             ccf
mmu.asm(130): error: Write outside of memory slot: 32768
130   8000 3F             ccf     ; should be error, second `ccf` left the slot memory
131   8001                  ASSERT {0x8000} == "7?"     ; but damage is done in the virtual memory, that's how it is
132   8001
133   8001              ;-----------------------------------------------------------
134   8001              ; new part: third ORG argument will now warn when it's outside of slot range
135   8001
136   8001                  MMU 0, 0, 0x3FFF
mmu.asm(137): warning: [MMU] Requested ORG address 0x4000 is out of range 0x0000..0x3FFF
137   3FFF                  MMU 0, 0, 0x4000            ; warn
mmu.asm(138): warning: [MMU] Requested ORG address 0x3FFF is out of range 0x4000..0x7FFF
138   4000                  MMU 1, 5, 0x3FFF            ; warn
139   3FFF                  MMU 1, 5, 0x4000
140   4000                  MMU 1, 5, 0x7FFF
mmu.asm(141): warning: [MMU] Requested ORG address 0x8000 is out of range 0x4000..0x7FFF
141   7FFF                  MMU 1, 5, 0x8000            ; warn
mmu.asm(142): warning: [MMU] Requested ORG address 0x3FFF is out of range 0x4000..0xBFFF
142   8000                  MMU 1 2, 5, 0x3FFF          ; warn
143   3FFF                  MMU 1 2, 5, 0x4000
144   4000                  MMU 1 2, 5, 0xBFFF
mmu.asm(145): warning: [MMU] Requested ORG address 0xC000 is out of range 0x4000..0xBFFF
145   BFFF                  MMU 1 2, 5, 0xC000          ; warn
mmu.asm(146): warning: [MMU] Requested ORG address 0xBFFF is out of range 0xC000..0xFFFF
146   C000                  MMU 3, 7, 0xBFFF            ; warn
147   BFFF                  MMU 3, 7, 0xC000
148   C000
# file closed: mmu.asm

Value    Label
------ - -----------------------------------------------------------
0x7FFE X label0_p4
0x7FFF X label1_p4
0x4000 X label2_p5
0x7FFF X label3_p5
