Home | History | Annotate | Line # | Download | only in !BtNetBSD
      1 REM > BtNetBSD
      2 REM $NetBSD: BtNetBSD,v 1.7 2025/08/18 20:59:54 andvar Exp $
      3 REM
      4 REM Copyright (c) 2000, 2001, 2002 Reinoud Zandijk
      5 REM Copyright (c) 1998, 1999, 2000 Ben Harris
      6 REM ELF file reading based on work by Ben Harris
      7 REM All rights reserved.
      8 REM
      9 REM Redistribution and use in source and binary forms, with or without
     10 REM modification, are permitted provided that the following conditions
     11 REM are met:
     12 REM 1. Redistributions of source code must retain the above copyright
     13 REM    notice, this list of conditions and the following disclaimer.
     14 REM 2. Redistributions in binary form must reproduce the above copyright
     15 REM    notice, this list of conditions and the following disclaimer in the
     16 REM    documentation and/or other materials provided with the distribution.
     17 REM 3. The name of the author may not be used to endorse or promote products
     18 REM    derived from this software without specific prior written permission.
     19 REM
     20 REM THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     21 REM IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     22 REM OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     23 REM IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     24 REM INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     25 REM NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26 REM DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27 REM THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28 REM (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     29 REM THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30 REM
     31 REM This file is part of NetBSD/acorn32 -- a port of NetBSD to ARM6+ machines
     32 REM This source contains pieces of code by Ben Harris (file structure)
     33 REM and Mark Brinicombe (DRAM/VRAM search)
     34 REM
     35 REM Purpose : Trying to boot NetBSD/acorn32 !!
     36 
     37 
     38 ON ERROR REPORT:PRINT " at line ";ERL: PRINT'"Press key":QQ=GET:END
     39 
     40 debug%           = 0
     41 emulateVRAM%     = 0
     42 emulateDRAMsize% = 0
     43 extradebug%      = 0
     44 startdelay%      = 5
     45 
     46 REM For Kinetic cards
     47 SDRAM_ADDR_START% = 512*1024*1024
     48 REM For debugging only :
     49 REM SDRAM_ADDR_START% = &18000000
     50 
     51 
     52 REM set pretty screen for printing without scrolling
     53 SYS "XWimp_CommandWindow", -1: VDU 26
     54 SYS "XHourglass_Smash"
     55 MODE MODE
     56 COLOUR 128+4:CLS
     57 scwidth% = FNvdu_var(256): scheigth% = FNvdu_var(257)
     58 width% = INT(scwidth%*0.75*0.5)*2: heigth% = INT(scheigth%*0.75*0.5)*2
     59 VDU 4, 28, (scwidth%-width%)/2, (scheigth%+heigth%)/2, (scwidth%+width%)/2, (scheigth%-heigth%)/2
     60 COLOUR 128:CLS
     61 
     62 PRINT''
     63 PROCcenter("BtNetBSD 0.99b")
     64 PROCcenter("booting NetBSD/acorn32 on a RiscPC/A7000/NC")
     65 PRINT''
     66 
     67 REM get argument string
     68 SYS "OS_GetEnv" TO args$
     69 WHILE LEFT$(args$, 1)=" ": args$=MID$(args$,2):ENDWHILE
     70 IF LEFT$(args$, 5)="BASIC" THEN args$=MID$(args$, 6)
     71 WHILE LEFT$(args$, 1)=" ": args$=MID$(args$,2):ENDWHILE
     72 IF LEFT$(args$, 5)="-quit" THEN args$=MID$(args$, 6)
     73 WHILE LEFT$(args$, 1)=" ": args$=MID$(args$,2):ENDWHILE
     74 prog$ = LEFT$(args$, INSTR(args$, " ")-1)
     75 args$ = MID$(args$, LEN(prog$)+1)
     76 WHILE LEFT$(args$, 1)=" ": args$=MID$(args$,2):ENDWHILE
     77 
     78 REM get kernel name
     79 file$ = LEFT$(args$, INSTR(args$, " ")-1)
     80 
     81 PRINT "Press return to boot now, any other key for boot prompt"
     82 PRINT "Booting ";file$;" ";args$
     83 PRINT "Starting in ";
     84 c% = FNawaitkey(5)
     85 IF c% <> 13 AND c% <> 0 THEN
     86   INPUT "Boot: " cmd$
     87   IF LEFT$(cmd$, 1) = "-" THEN
     88     REM just add an option
     89     args$ += " " + cmd$
     90   ELSE
     91     args$ = cmd$
     92     file$ = LEFT$(args$, INSTR(args$, " ") - 1)
     93   ENDIF
     94   PRINT "Booting ";file$;" ";args$
     95 ENDIF
     96 PRINT''
     97 
     98 
     99 IF FNtolower(LEFT$(file$,9))="unixfs:$." THEN
    100   kernelname$=MID$(file$, 10)
    101 ELSE
    102   kernelname$="netbsd" : REM RISC OS file namen zeggen niets XXX
    103 ENDIF
    104 
    105 
    106 REM Get some space to mess with
    107 REM Declare a large array ... and then wipe it/map it in in the OS_Mem loop
    108 REM the difference is that RO4 won't map it in by default and
    109 REM that could trigger a OS_Memory bug ...
    110 SYS "OS_Memory", 6 TO ,memorytablesize%, nbpp% : REM get tablesize%
    111 memory_image_size% = HIMEM-512*1024            : REM keep a 512 Kb for vars
    112 DIM memory_image% memory_image_size%           : REM claim the space
    113 
    114 bot_memory% = memory_image%
    115 top_memory% = memory_image% + memory_image_size%
    116 
    117 KERNEL_BASE = &F0000000
    118 
    119 MAX_RELOCPAGES = 4096
    120 MAX_DRAMBANKS = 32
    121 MAX_VRAMBANKS = 16
    122 
    123 twirl% = 0
    124 firstpage%  = (bot_memory% DIV nbpp%)+1
    125 lastpage%   = (top_memory% DIV nbpp%)-1
    126 totalpages% = lastpage% - firstpage%
    127 PRINT "I got a ";totalpages%;" memory pages to mess with"
    128 
    129 relocsize% = (MAX_RELOCPAGES+1)*12
    130 DIM relocinstr% relocsize%
    131 relocpos% = relocinstr%+4 : REM first word in number of relocations
    132 relocnr% = 0: relocoff% = 0
    133 
    134 REM this memory block contains all information about the memory layout
    135 REM maybe a bug in BASIC but if I DIM this variable in a procedure it
    136 REM gets on the stack or so ? It malfunctions if I pass this on as a
    137 REM procedure variable.
    138 DIM memoryblock% (totalpages%*12+4)
    139 
    140 PROCget_memory_configuration
    141 PROCget_memory_map
    142 
    143 PROCload_kernel(file$)
    144 PROCcreate_initial_pagetables
    145 PROCadd_pagetables
    146 PROCcreate_configuration
    147 
    148 REM now only the relocation code itself and then copying the relocation table itself
    149 !relocinstr% = relocnr%
    150 PROCcreate_relocate_mechanism
    151 PRINT " "
    152 
    153 REM start the kernel
    154 A% = FNblock_paddr(configurationbasepage%)
    155 B% = physical_start_address% - FNblock_vaddr(relocatebasepage%) + FNblock_paddr(relocatebasepage%)
    156 C% = FNblock_paddr(relocatebasepage%) + nbpp% : REM one page after the code
    157 D% = L1pages_phys%
    158 E% = entry%
    159 
    160 IF debug% THEN
    161   IF ((relocpos%-(relocinstr%+4)) MOD 12)<>0 THEN ERROR 0,"Sanity check for relocation entries failed!"
    162   PRINT"Entering kernel at 0x";~entry%
    163   REM  OSCLI("Memoryi "+STR$~(FNblock_vaddr(start_kernelpage%)+(entry% MOD nbpp%)))
    164   REM  PRINT"Go for it (key)":qq=GET
    165 ENDIF
    166 
    167 REM get ECID for each podule
    168 FOR pod% =-1 TO 8
    169   SYS "XPodule_ReadID",,,,pod%
    170 NEXT
    171 
    172 REM shut down RiscOS
    173 SYS "XOS_CLI", "RMKill UnixFS"
    174 SYS "OS_FSControl", 23     : REM close files etc.
    175 SYS "OS_ServiceCall",, &45 : REM prereset
    176 
    177 REM Remove all cursors
    178 *pointer 0
    179 SYS "OS_RemoveCursors"
    180 
    181 REM Change screen's base address (VDU/displayed) to offset 0
    182 DIM buf 8
    183 buf?3 = 3: buf!4 = 0: SYS "OS_Word", 22, buf+3
    184 
    185 CALL relocate_entry%
    186 
    187 END
    188 
    189 
    190 DEF PROCload_kernel(file$)
    191   LOCAL file%, magic%
    192   file% = OPENIN(file$)
    193   IF file% = 0 THEN ERROR EXT 1, "Can't open kernel"
    194     DIM magic% 3
    195   SYS "OS_GBPB", 3, file%, magic%, 4, 0
    196   IF magic%?0 = 127 AND magic%?1 = ASC("E") AND magic%?2 = ASC("L") AND magic%?3 = ASC("F") THEN
    197     PROCload_kernel_elf(file%)
    198   ELSE
    199     PROCload_kernel_aout(file%)
    200   ENDIF
    201   CLOSE#file%
    202 ENDPROC
    203 
    204 
    205 
    206 REM *****************************************************************************
    207 REM * ELF LOADER                                                                *
    208 REM *****************************************************************************
    209 
    210 
    211 DEF PROCload_kernel_elf(file%)
    212   REM read header
    213   DIM hdr% 52
    214   SYS "OS_GBPB", 3, file%, hdr%, 52, 0
    215  
    216   REM check if its a correct kernel to load
    217   IF hdr%?4 <> 1 THEN ERROR 1, "Not a 32-bit ELF file"
    218   IF hdr%?5 <> 1 THEN ERROR 1, "Not an LSB ELF file"
    219   IF hdr%?6 <> 1 THEN ERROR 1, "Not a version-1 ELF file"
    220   REM hdr%?7 is EI_OSABI.  Should it be 255 (ELFOSABI_STANDALONE)?
    221   IF (hdr%!16 AND &FFFF) <> 2 THEN ERROR 1, "Not an executable ELF file"
    222   IF (hdr%!18 AND &FFFF) <> 40 THEN ERROR 1, "Not an ARM ELF file"
    223 
    224   PRINT "(ELF) ";
    225   REM read kernel characteristics and headers
    226   entry% = hdr%!24
    227   phoff% = hdr%!28
    228   shoff% = hdr%!32
    229   phentsize% = hdr%!42 AND &FFFF
    230   phnum% = hdr%!44 AND &FFFF
    231   shentsize% = hdr%!46 AND &FFFF
    232   shnum% = hdr%!48 AND &FFFF
    233   DIM phdrs% phnum% * phentsize% - 1  : REM array with headers ?
    234   SYS "OS_GBPB", 3, file%, phdrs%, phnum% * phentsize%, phoff%
    235   IF phnum% = 0 THEN ERROR 1, "No program headers"
    236 
    237   REM start loading !
    238   freepagesbase% = first_mapped_DRAM_index% : REM == first virt address in DRAM0a
    239   start_kernelpage% = freepagesbase%
    240   pv_offset% = KERNEL_BASE - DRAM_addr%(0) : REM XXX hardcoded
    241 
    242   REM load the program blocks
    243   first% = TRUE
    244   FOR ph% = phdrs% TO phdrs% + (phnum% - 1) * phentsize% STEP phentsize%
    245     IF ph%!0 = 1 THEN
    246       REM We only do PT_LOAD
    247       IF NOT first% THEN PRINT "+";
    248       first%  = FALSE
    249       offset% = ph%!4
    250       vaddr%  = ph%!8
    251       REM physaddr% = ph%!12
    252       filesz% = ph%!16
    253       memsz%  = ph%!20
    254       flags%  = ph%!24
    255       PROCload_chunk(file%, offset%, vaddr%, filesz%, memsz%)
    256       REM freepagesbase% is updated
    257 
    258       vfreebase% = vaddr% + memsz% : REM memsz% is the real size.... filesz can be only Text f.e.
    259     ENDIF
    260   NEXT
    261 
    262   txtbase% = 0
    263   txtsize% = 0
    264   database% = 0
    265   datasize% = 0
    266   bssbase% = 0
    267   bsssize% = 0
    268   ssym% = 0
    269   esym% = 0
    270 
    271   DIM shdrs% shnum% * shentsize% - 1
    272   SYS "OS_GBPB", 3, file%, shdrs%, shnum% * shentsize%, shoff%
    273   IF shnum% <> 0 THEN
    274     havesyms% = FALSE
    275     FOR sh% = shdrs% TO shdrs% + (shnum% - 1) * shentsize% STEP shentsize%
    276       IF sh%!4 = 2 THEN havesyms% = TRUE
    277     NEXT
    278     IF havesyms% THEN
    279       IF INSTR(args$, "symtab")=0 THEN havesyms% = FALSE
    280       IF debug% THEN
    281         IF havesyms% PRINT ;" (symbols avail) "; ELSE PRINT ;" (ignoring symbols) ";
    282       ENDIF
    283     ENDIF
    284     REM freepagesbase% points to first free relocation page
    285     IF havesyms% THEN
    286       REM vfreebase points to first free address in relocated area
    287       PRINT "+[";
    288 
    289       REM First, we have the munged ELF header
    290       ssym% = vfreebase%
    291       ssympage% = freepagesbase%
    292       PROCload_chunk(file%, 0, ssym%, 52, 52)
    293       !(FNblock_vaddr(ssympage%) + 32) = 52: REM  PROCwrite_word(ssym%+32, 52)
    294       vfreebase% += 52
    295 
    296       REM then, the munged section headers
    297       mshdrs% = vfreebase%
    298       mshdrspage% = freepagesbase%
    299       PRINT "+";
    300       PROCload_chunk(file%, shoff%, mshdrs%, shnum% * shentsize%, shnum% * shentsize%)
    301       vfreebase% += shnum% * shentsize%
    302       FOR sh% = shdrs% TO shdrs% + (shnum% - 1) * shentsize% STEP shentsize%
    303         IF sh%!4 = 2 OR sh%!4 = 3 THEN
    304           PRINT "+";
    305           PROCload_chunk(file%, sh%!16, vfreebase%, sh%!20, sh%!20)
    306           !(FNblock_vaddr(mshdrspage%) + sh% - shdrs% + 16) = vfreebase% - ssym%
    307           vfreebase% += FNroundup(sh%!20, 4)
    308         ENDIF
    309       NEXT
    310       esym% = vfreebase%
    311       PRINT "]";
    312     ENDIF
    313   ENDIF
    314   PRINT " ";
    315 
    316   kernelpages% = freepagesbase% - start_kernelpage%
    317   IF extradebug% THEN PRINT ''"Number of kernel pages ";kernelpages%;" (";kernelpages%*nbpp%;" bytes)"
    318 
    319   PROCfinish_relocationtable
    320 ENDPROC
    321 
    322 
    323 DEF PROCload_chunk(file%, offset%, vaddr%, filesz%, memsz%)
    324   LOCAL paddr%, ppn%, fragaddr%, fragsz%
    325 
    326   REM offset%  offset in file
    327   REM vaddr%   indicates virtual address where stuff needs to be relocated to
    328   REM filesz%  number of bytes to read of `file' for this chunk
    329   REM memsz%   number of bytes to clear for this chunk
    330   PRINT ;filesz%;
    331   IF extradebug% PRINT ;" (";~vaddr%;"-";~(vaddr%+memsz%);" [till base+";INT((vaddr%+memsz%-&F0000000)/1024);"k]) ";
    332   WHILE filesz% > 0
    333     REM freepagesbase% is first page index in freepages list
    334     fragsz% = nbpp%
    335     IF fragsz% > filesz% THEN fragsz% = filesz%
    336 
    337     fragaddr% = FNblock_vaddr(freepagesbase%)
    338     SYS "OS_GBPB", 3, file%, fragaddr%, fragsz%, offset%
    339  
    340     REM create a relocation block
    341     relocpos%!0 = FNblock_paddr(freepagesbase%)
    342     relocpos%!4 = vaddr% - pv_offset%
    343     relocpos%!8 = fragsz%
    344     relocpos% += 12: relocnr%+=1: relocoff%+=1
    345     freepagesbase% += 1
    346 
    347     offset% += fragsz%
    348     vaddr% += fragsz%
    349     filesz% -= fragsz%
    350     memsz% -= fragsz%
    351     PROCtwirl
    352   ENDWHILE
    353  
    354   IF memsz% > 0 PRINT "+";memsz%;
    355   WHILE memsz% > 0
    356     REM freepagesbase% is first page index in freepages list
    357     fragsz% = nbpp%
    358     IF fragsz% > memsz% THEN fragsz% = memsz%
    359 
    360     PROCbzero(FNblock_vaddr(freepagesbase%), fragsz%)
    361 
    362     REM create a relocation block
    363     relocpos%!0 = FNblock_paddr(freepagesbase%)
    364     relocpos%!4 = vaddr% - pv_offset%
    365     relocpos%!8 = fragsz%
    366     relocpos% += 12: relocnr%+=1: relocoff%+=1
    367     freepagesbase% += 1
    368  
    369     offset% += fragsz%
    370     vaddr% += fragsz%
    371     filesz% -= fragsz%
    372     memsz% -= fragsz%
    373     PROCtwirl
    374   ENDWHILE
    375 ENDPROC
    376 
    377 
    378 REM *****************************************************************************
    379 REM * A.OUT LOADER                                                              *
    380 REM *****************************************************************************
    381 
    382 DEF PROCload_kernel_aout(file%)
    383   LOCAL hdr%
    384   DIM hdr% 32
    385   ssym% = 0 : esym% = 0
    386   SYS "OS_GBPB", 3, file%, hdr%, 32, 0
    387   bemagic% = (hdr%?0 << 24) OR (hdr%?1 <<16) OR (hdr%?2 << 8) OR hdr%?3
    388   CASE bemagic% AND &0000FFFF OF
    389     WHEN &0107
    390       PRINT "(OMAGIC) ";
    391     WHEN &0108
    392       PRINT "(NMAGIC) ";
    393     WHEN &010B
    394       PRINT "(ZMAGIC) ";
    395     WHEN &00CC
    396       PRINT "(QMAGIC) ";
    397   ENDCASE
    398   REM XXX: Assume ZMAGIC
    399 
    400   REM foooff% is byte offset in file.  foobasepage% is base page in RAM.
    401   txtoff% = 0 : REM in arm26 its 4096
    402   txtbasepage% = first_mapped_DRAM_index% : REM == first virt address in DRAM0a
    403   start_kernelpage% = txtbasepage%
    404 
    405   txtsize% = hdr%!4
    406   IF txtsize% MOD nbpp% <> 0 THEN
    407     ERROR EXT 1, "Text size not a multiple of page size"
    408   ENDIF
    409   txtpages% = txtsize% DIV nbpp%
    410   dataoff% = txtoff% + txtsize%
    411   databasepage% = txtbasepage% + txtpages%
    412   database% = databasepage% * nbpp%
    413   datasize% = hdr%!8
    414   IF datasize% MOD nbpp% <> 0 THEN
    415     ERROR EXT 1, "Data size not a multiple of page size"
    416   ENDIF
    417   datapages% = datasize% DIV nbpp%
    418   bssbasepage% = databasepage% + datapages%
    419   bssbase% = bssbasepage% * nbpp%
    420   bsspages% = FNroundup(hdr%!12, nbpp%) DIV nbpp%
    421   bsssize% = bsspages% * nbpp%
    422   IF bsssize% MOD nbpp% <> 0 THEN
    423     ERROR EXT 1, "Bss size not a multiple of page size"
    424   ENDIF
    425  
    426   entry% = hdr%!20
    427   IF debug% THEN PRINT "Entry point at ";~entry%
    428 
    429   REM kernelpages without syms table is :
    430   kernelpages% = txtpages% + datapages% + bsspages% : REM
    431 
    432   REM  symbasepage% = bssbasepage% + bsspages%-1 : REM REAL size... not in pages
    433   symoff% = dataoff% + datasize%
    434   symsize% = hdr%!16
    435   stringtablesize% = EXT#file% - (txtsize% + datasize% + symsize%)
    436   IF INSTR(args$, "symtab")>0 THEN
    437     kernelpages% += FNroundup(stringtablesize% + symsize% + 4, nbpp%) DIV nbpp%
    438   ELSE
    439     symsize% = 0
    440     stringtablesize% = 0
    441   ENDIF
    442   REM reserve 1 extra word for the length
    443   symbolsize% = symsize% + stringtablesize% + 4
    444   symbolpages% = FNroundup(symbolsize%, nbpp%) DIV nbpp%
    445   IF debug% PRINT '"Stringtablesize = 0x";~stringtablesize%;"  symsize = 0x";~symsize%
    446  
    447   PRINT '"A total of about ";kernelpages%;" pages need to be relocated"
    448   IF (kernelpages%+40)*nbpp% > memory_image_size% THEN
    449     REM 40 is an estimation ...
    450     ERROR EXT 1, "Not enough memory free... please increase WimpSlot in the configuration file"
    451   ENDIF
    452 
    453   PRINT ;txtsize%;
    454   new_hdr% = FNblock_vaddr(txtbasepage%)
    455   FOR pg% = 0 TO txtpages%-1
    456     SYS "OS_GBPB", 3, file%, FNblock_vaddr(txtbasepage%+pg%), nbpp%, txtoff% + pg%*nbpp%
    457     relocpos%!0 = FNblock_paddr(txtbasepage%+pg%)
    458     relocpos%!4 = kernel_phys_start% + nbpp%*relocoff%: relocnr%+=1: relocoff%+=1
    459     relocpos%!8 = nbpp%
    460     relocpos% += 12
    461     PROCtwirl
    462   NEXT
    463 
    464   PRINT "+";datasize%;
    465   FOR pg% = 0 TO datapages%-1
    466     SYS "OS_GBPB", 3, file%, FNblock_vaddr(databasepage%+pg%), nbpp%, dataoff% + pg%*nbpp%
    467     relocpos%!0 = FNblock_paddr(databasepage%+pg%)
    468     relocpos%!4 = kernel_phys_start% + nbpp%*relocoff%: relocnr%+=1: relocoff%+=1
    469     relocpos%!8 = nbpp%
    470     relocpos% += 12
    471     PROCtwirl
    472   NEXT
    473   REM PRINT;"(";off%;" gaps)";
    474 
    475   PRINT "+";bsssize%;
    476   FOR pg% = 0 TO bsspages%-1 : REM overshoot is safe
    477     PROCbzero(FNblock_vaddr(bssbasepage%+pg%), nbpp%)
    478     relocpos%!0 = FNblock_paddr(bssbasepage%+pg%)
    479     relocpos%!4 = kernel_phys_start% + nbpp%*relocoff%: relocnr%+=1: relocoff%+=1
    480     relocpos%!8 = nbpp%
    481     relocpos% += 12
    482     PROCtwirl
    483   NEXT
    484   REM PRINT;"(";off%;" gaps)";
    485 
    486   freepagesbase% = bssbasepage% + bsspages%
    487 
    488   IF INSTR(args$, "symtab")>0 THEN
    489     symbasepage% = freepagesbase%
    490 
    491     REM put a page for the value of symsize just after bss%
    492     symDaddr% = !(relocpos%-8) + ((hdr%!12) AND (nbpp%-1))
    493  
    494     symstartpagaddrV% = FNblock_vaddr(symbasepage%)
    495     PROCbzero(symstartpagaddrV%, nbpp%)
    496     !symstartpagaddrV% = symsize%
    497 
    498     relocpos%!0 = FNblock_paddr(symbasepage%)
    499     relocpos%!4 = symDaddr%  : relocnr%+=1: relocoff%+=1
    500     relocpos%!8 = nbpp% : REM XXX
    501     relocpos% += 12
    502     symDaddr% += 4
    503  
    504     REM update the symbasepage !! ... we used one!
    505     symbasepage%+=1
    506  
    507     PRINT "+";symbolsize%;
    508     REM now fill in rest of the file
    509     FOR pg% = 0 TO symbolpages%-1 : REM => due to first page to hold offset
    510       SYS "OS_GBPB", 3, file%, FNblock_vaddr(symbasepage%+pg%), nbpp%, symoff% + pg%*nbpp%
    511       relocpos%!0 = FNblock_paddr(symbasepage%+pg%)
    512       relocpos%!4 = symDaddr% + nbpp%*pg%: relocnr%+=1: relocoff%+=1
    513       relocpos%!8 = nbpp%
    514       relocpos% += 12
    515       PROCtwirl
    516     NEXT
    517  
    518     freepagesbase% = symbasepage% + symbolpages% + 4 : REM XXX
    519   ENDIF
    520  
    521   REM update new header structure
    522   new_hdr%!16 = symsize%
    523  
    524   REM mark highest virtual address free in NetBSD's mapping
    525   vfreebase% = KERNEL_BASE + nbpp%*relocoff%
    526 
    527   REM `patch' symbol table stuff
    528   ssym% = 0
    529   esym% = 0
    530  
    531   PROCfinish_relocationtable
    532 ENDPROC
    533 
    534 
    535 REM *****************************************************************************
    536 REM * Common loader and relocate stuff                                          *
    537 REM *****************************************************************************
    538 
    539 DEF PROCfinish_relocationtable
    540   REM align vfreebase% to a page
    541   vfreebase% = FNroundup(vfreebase%, nbpp%)
    542   relocoff% = (vfreebase% - KERNEL_BASE) DIV nbpp%
    543 
    544   IF vfreebase% > (nbpp%*relocoff% + KERNEL_BASE) THEN
    545     PRINT ''"WHOOAH!' : 0x", ~vfreebase%;" > 0x";~(nbpp%*relocoff%+KERNEL_BASE)
    546     freepagesbase% += 16
    547     kernelpages%   += 16
    548     relocoff%      += 16
    549   ENDIF
    550 
    551   IF INSTR(args$, "oldkernel")>0 THEN
    552     REM place the arguments in a block ... for the old bootloader's sake
    553     argsbasepage% = freepagesbase%
    554     argspages% = 1
    555     argvirtualbase% = nbpp%*relocoff% + KERNEL_BASE
    556     relocpos%!0 = FNblock_paddr(argsbasepage%)
    557     relocpos%!4 = kernel_phys_start% + nbpp%*relocoff%: relocnr%+=1: relocoff%+=1
    558     relocpos%!8 = nbpp%
    559     relocpos% += 12
    560     $(FNblock_vaddr(argsbasepage%)) = args$+CHR$0
    561     freepagesbase% += argspages%
    562     kernelpages%   += argspages%
    563     IF debug% THEN PRINT "Args at 0x";~argvirtualbase%
    564   ELSE
    565     REM reserve some space for the MDF file
    566     REM XXX not implemented yet XXX
    567   ENDIF
    568 
    569   REM I give it a 48k scratch space
    570   scratchbasepage% = freepagesbase%
    571   scratchpages% = 12
    572   scratchvirtualbase% = nbpp%*relocoff% + KERNEL_BASE
    573   freepagesbase% += scratchpages%
    574   kernelpages%   += scratchpages%
    575 
    576   REM Create one page for the initial vectors
    577   initvectorbasepage% = freepagesbase%
    578   initvectorpages%    = 1
    579   relocpos%!0 = FNblock_paddr(initvectorbasepage%)
    580   relocpos%!4 = top_physdram% - 1*1024*1024 : relocnr%+=1
    581   relocpos%!8 = nbpp%
    582   relocpos% += 12
    583   freepagesbase% += initvectorpages%
    584 
    585   P%=FNblock_vaddr(initvectorbasepage%)
    586   FOR vec=0 TO &20 STEP 4
    587     [OPT 2: MOVS PC, r14:]
    588   NEXT
    589 ENDPROC
    590 
    591 
    592 DEF PROCadd_pagetables
    593   REM DESTINATION MUST BE ON A 16kb boundary!!! (!!!!)
    594   REM get 4 pages on the top of physical memory (top_physdram%) and copy PT's in it
    595   addr% = top_physdram% - 4*nbpp%
    596   IF (addr% AND (16*1024-1)) <> 0 ERROR EXT 0, "L1 pages not on 16Kb boundary"
    597   FOR pg%=0 TO 3
    598     PROCcopy(FNblock_vaddr(freepagesbase% + pg%), bootpagetables% + pg%*nbpp%, nbpp%)
    599     relocpos%!0 = FNblock_paddr(freepagesbase%+pg%)
    600     relocpos%!4 = addr%+pg%*nbpp%: relocnr%+=1
    601     relocpos%!8 = nbpp%
    602     relocpos% += 12
    603   NEXT
    604   L1pages_phys% = addr%
    605   freepagesbase% = freepagesbase%+pg%
    606 ENDPROC
    607 
    608 
    609 DEF PROCcreate_initial_pagetables
    610   LOCAL I%, addr%, kaddr%, mapped_screenmemory%
    611   DIM bootpagetables% 16*1024
    612   REM linear translation on the whole domain 00 in blocks of 1Mb
    613   REM AP=%01, CB=%00 for easy initial setup, dom=0
    614   FOR I%=0 TO 4*1024-1
    615     bootpagetables%!(I%*4) = (I%<<20) + (0<<11)+(1<<10) + (1<<4) + (0<<3) + (0<<2) + (1<<1) + 0
    616   NEXT
    617 
    618   REM video memory is mapped 1:1 in the DRAM section or in VRAM section
    619 
    620   REM map 1Mb from top of memory to bottom 1Mb of virt. memmap
    621   addr% = (top_physdram%/1024/1024) -1
    622   bootpagetables%!0 = (addr%<<20) + (0<<11)+(1<<10) + (1<<4) + (0<<3) + (0<<2) + (1<<1) + 0
    623 
    624   REM map 16 Mb of DRAM0a (kernel space) to 0xf0000000
    625   FOR I%=0 TO 15
    626     addr% = (kernel_phys_start% >> 20) + I%
    627     kaddr% = &F00 + I% : REM &F0000000 LSR #20 + I%
    628     bootpagetables%!(kaddr%*4) = (addr%<<20) + (0<<11)+(1<<10) + (1<<4) + (0<<3) + (0<<2) + (1<<1) + 0
    629   NEXT
    630 ENDPROC
    631 
    632 
    633 DEF PROCcreate_relocate_mechanism
    634   REM relocate mechanism relies on a contigunous space of the relocator + tables
    635   REM this isn't finished yet
    636 
    637   relocatesize% = nbpp% + relocsize% : REM just ONE code page + relocation table
    638   PRINT ;"+";relocatesize%;
    639   relocatepages% = FNroundup(relocatesize%, nbpp%) DIV nbpp%
    640   relocatebasepage% = freepagesbase%
    641   pg%=0
    642   WHILE pg%<relocatepages%
    643     IF pg%>0 THEN
    644       PROCcopy(FNblock_vaddr(relocatebasepage%+pg%), relocinstr%+(pg%-1)*nbpp%, nbpp%)
    645     ENDIF
    646     PROCtwirl
    647 
    648     IF pg%<>relocatepages%-1 THEN
    649       IF FNblock_paddr(relocatebasepage%+pg%+1)-FNblock_paddr(relocatebasepage%+pg%)<>nbpp% THEN
    650         REM Help! non contigunous relocate area => try again
    651         REM ERROR EXT 0, "Help! non contigunous relocate area"
    652         PRINT ;"*";
    653         relocatebasepage% = freepagesbase% + pg% : REM  try again from this page
    654         pg%=-1 : REM will be auto incremented later ...
    655       ENDIF
    656     ENDIF
    657     pg%+=1
    658   ENDWHILE
    659   PROCassemble_relocate_code(FNblock_vaddr(relocatebasepage%), FNblock_paddr(relocatebasepage%), entry%, L1pages_phys%)
    660 ENDPROC
    661 
    662 
    663 DEF PROCcreate_configuration
    664   PRINT ;"+";nbpp%;
    665   configurationbasepage% = freepagesbase%
    666   configurationpages% = 1
    667   freepagesbase% += configurationpages%
    668 
    669   REM fatal(swix(OS_ReadSysInfo, IN(R0)|OUT(R3), 2, &bootconfig.machine_id));
    670   SYS "OS_ReadSysInfo", 2 TO r0,r1,r2, machineId%
    671 
    672   IF INSTR(args$, "oldkernel")>0 THEN
    673     PROCold_configuration_structure
    674   ELSE
    675     PROCnew_configuration_structure
    676   ENDIF
    677 ENDPROC
    678 
    679 
    680 DEF PROCnew_configuration_structure
    681   FOR opt%=0 TO 2 STEP 2
    682     P% = FNblock_vaddr(configurationbasepage%)
    683     [OPT opt%
    684     ; u_int magic
    685         EQUD          &43112233 ; BOOTCONFIG_MAGIC
    686     ; u_int bootconfig_version
    687         EQUD          2
    688 
    689     ; u_char machine_id[4]
    690         EQUD          machineId%
    691     ; char kernelname[80]
    692         EQUS          LEFT$(kernelname$+CHR$0+STRING$(80, " "), 80)
    693     ; char args[512]
    694         EQUS          args$+CHR$0
    695         ]: P% += 512 - LEN(args$+CHR$0): [ OPT opt%
    696 
    697     ; u_int kernvirtualbase             /* not used now */
    698         EQUD 0
    699     ; u_int kernphysicalbase            /* not used now */
    700         EQUD 0
    701     ; u_int kernsize
    702         EQUD          kernelpages% * nbpp%
    703     ; u_int scratchvirtualbase
    704         EQUD          scratchvirtualbase%
    705     ; u_int scratchphysicalbase
    706         EQUD          scratchvirtualbase%
    707     ; u_int scratchsize
    708         EQUD          scratchpages% * nbpp%
    709 
    710     ; u_int ksym_start
    711         EQUD ssym%
    712     ; u_int ksym_end
    713         EQUD esym%
    714 
    715     ; u_int MDFvirtualbase
    716         EQUD 0
    717     ; u_int MDFphysicalbase
    718         EQUD 0
    719     ; u_int MDFsize
    720         EQUD 0
    721  
    722     ; u_int display_phys
    723         EQUD          videomem_start%
    724     ; u_int display_start
    725         EQUD          videomem_start% ; screenstart (149)
    726     ; u_int display_size
    727         EQUD          display_size%   ; screensize  (150)
    728     ; u_int width
    729         EQUD          FNvdu_var(11)   ; acorn32 port needs 0..x-1
    730     ; u_int heigth
    731         EQUD          FNvdu_var(12)   ; acorn32 port needs 0..y-1
    732     ; u_int log2_bpp
    733         EQUD          FNvdu_var(9)    ; acorn32 port needs log(bitsperpixel)/log(2)
    734     ; u_int framerate
    735         EQUD          56 ; XXX why?
    736  
    737     ; char reserved[512]
    738     ]: P% += 512: [ OPT opt%
    739  
    740     ; u_int pagesize
    741         EQUD          nbpp%
    742     ; u_int drampages
    743         EQUD          totaldrampages%
    744     ; u_int vrampages;
    745         EQUD          totalvrampages%
    746     ; u_int dramblocks
    747         EQUD          dramblocks%
    748     ; u_int vramblocks
    749         EQUD          vramblocks%
    750 
    751     ]
    752     REM phys_mem dram[DRAM_BLOCKS]  <- 32
    753     FOR I%=0 TO MAX_DRAMBANKS-1
    754       [OPT opt%
    755         ; address% : EQUD DRAM_addr%(I%)
    756         ; length%  : EQUD DRAM_pages%(I%)
    757         ; flags%   : EQUD 0
    758       ]
    759     NEXT
    760     REM phys_mem vram[VRAM_BLOCKS]  <- 16
    761     FOR I%=0 TO MAX_VRAMBANKS-1
    762       [OPT opt%
    763         ; address% : EQUD VRAM_addr%(I%)
    764         ; length%  : EQUD VRAM_pages%(I%)
    765         ; flags%   : EQUD 0
    766       ]
    767     NEXT
    768   NEXT
    769 ENDPROC
    770 
    771 
    772 DEF PROCold_configuration_structure
    773   FOR opt%=0 TO 2 STEP 2
    774     P% = FNblock_vaddr(configurationbasepage%)
    775     [OPT opt%
    776     ;kernvirtualbase%
    777         EQUD          0   ; not used
    778     ;kernphysicalbase%
    779         EQUD          0   ; not used
    780     ;kernsize%
    781         EQUD          kernelpages% * nbpp%
    782     ;argvirtualbase
    783         EQUD          argvirtualbase%
    784     ;argphysicalbase
    785         EQUD          FNblock_paddr(argsbasepage%)
    786     ;argsize%
    787         EQUD          nbpp%
    788     ;scratchvirtualbase%
    789         EQUD          scratchvirtualbase%
    790     ;scratchphysicalbase%
    791         EQUD          scratchvirtualbase%
    792     ;scratchsize%
    793         EQUD          scratchpages% * nbpp%
    794     ;display_start%
    795         EQUD          videomem_start% ; screenstart (149)
    796     ;display_size%
    797         EQUD          display_size%   ; screensize  (150)
    798     ;width%
    799         EQUD          FNvdu_var(11)   ; arm32 port needs 0..x-1
    800     ;height%
    801         EQUD          FNvdu_var(12)   ; arm32 port needs 0..y-1
    802     ;bitsperpixel
    803         EQUD          FNvdu_var(9)    ; arm32 port needs log(bitsperpixel)/log(2)
    804     ]
    805     REM for compatibility for now just 4 DRAM and 1 VRAM
    806     FOR I%=0 TO 3
    807       [OPT opt%
    808         ;address% : EQUD DRAM_addr%(I%)
    809         ;length%  : EQUD DRAM_pages%(I%)
    810       ]
    811     NEXT
    812     REM current config structure only wants 1 VRAM entry !
    813     FOR I%=0 TO 0
    814       [OPT opt%
    815         ;address% : EQUD VRAM_addr%(I%)
    816         ;length%  : EQUD VRAM_pages%(I%)
    817       ]
    818     NEXT
    819     [OPT opt%
    820     ;c_dramblocks%
    821         EQUD          dramblocks%
    822     ;c_vramblocks%
    823         EQUD          vramblocks%
    824     ;pagesize%
    825         EQUD          nbpp%
    826     ;drampages%
    827         EQUD          totaldrampages%
    828     ;vrampages%
    829         EQUD          totalvrampages%
    830     ;kernelname%
    831         EQUS          LEFT$(kernelname$+CHR$0+STRING$(80, " "), 80)
    832     ;framerate%
    833         EQUD          56 ; XXXXX
    834     ;machine_id%
    835         EQUD          machineId%
    836     ;magic%
    837         EQUD          &43112233 ; BOOTCONFIG_MAGIC
    838     ;display_phys%
    839         EQUD          videomem_start%
    840     ]
    841   NEXT opt%
    842 ENDPROC
    843 
    844 
    845 REM XXXX a bit messy still
    846 DEF PROCassemble_relocate_code(virtaddress%, physaddress%, entry%, L1pages_phys%)
    847   FOR opt%=0 TO 2 STEP 2
    848     P%=virtaddress%
    849     [OPT opt%
    850       ; entry conditions :
    851       ;   - on RiscOS page tables in usr26 mode on virt address ....
    852       ;   - R0  pointer to configuration structure
    853       ;   - R1  pointer to physical restart point
    854       ;   - R2  pointer to physical relocation table
    855       ;   - R3  pointer to physical new L1 page address
    856       ;   - R4  new virt adres of kernel entry%
    857       .relocate_entry%
    858         ; Enter sup26 mode
    859         SWI "OS_EnterOS"
    860  
    861         ; move args up in register bank
    862         STMFD r13!, {r0-r4}
    863         LDMFD r13!, {r8-r12}
    864 
    865         ; r8  = config structure address
    866         ; r9  = physical restart point address
    867         ; r10 = physical relocation table address
    868         ; r11 = physical address of new L1page
    869         ; r12 = kernel entry point in new virt. map
    870  
    871         ; go to sup32 mode with IRQ + FIQ disabled
    872         EQUD %11100001000011110000000000000000 ; MRS R0, CPSR
    873         BIC r0, r0, #&1F                       ; clear proc. mode
    874         ORR r0, r0, #(1<<7) + (1<<6)           ; set FIQ + IRQ disable
    875         ORR r0, r0, #%10011                    ; superv. 32 bit
    876         EQUD %11100001001010011111000000000000 ; MSR CPSR, r0
    877         MOV r0, r0
    878         MOV r0, r0                             ; nops ... nessisary?
    879 
    880         ; flush data cache
    881         ; just read a 64kb app space in the cache
    882         MOV r0, #&8000
    883         ADD r1, r0, r0
    884       .loop_flush1
    885         LDR r2, [r0], #4
    886         SUBS r1, r1, #4
    887         BNE loop_flush1
    888 
    889         ; determine processor type ... nessisary for correct copro instr .. store in r13
    890         EQUD %11101110000100000000111100010000 ; MRC cp15, 0, r0, c0, c0, 0 ; read CPU Id in r0
    891         MOV   r13, r0                          ; store in r13
    892 
    893         ; determine if its a StrongARM
    894         MOV   r14, #1                          ; r14 flags if its a StrongARM ... assume one
    895  
    896         ; detecting an ARM6 needs a special mask
    897         MOV   r0,     #&FF000000               ; get processor discr. mask in r0
    898         ADD   r0, r0, #&00000F00               ;
    899 
    900         MOV   r1,     #&41000000               ; check for 0x41xxx6xx => ARM6
    901         ADD   r1, r1, #&00000600
    902         AND   r2, r13, r0                      ; mask with discr. mask
    903         CMP   r2, r1                           ; is it a ARM6 ?
    904         MOVEQ r14, #0                          ; ifso ... then its a v3
    905  
    906         ; newer ARMs need a different mask
    907         MOV   r0,     #&FF000000               ; get processor discr. mask in r0
    908         ADD   r0, r0, #&0000F000               ;
    909 
    910         MOV   r1,     #&41000000               ; check for 0x41xx7xxx => ARM7
    911         ADD   r1, r1, #&00007000
    912         AND   r2, r13, r0                      ; mask with discr. mask
    913         CMP   r2, r1                           ; is it a ARM7 ?
    914         MOVEQ r14, #0                          ; ifso ... then its a v3
    915  
    916 ;        MOV   r1,     #&44000000               ; check for 0x44xxaxxx => Strong ARM
    917 ;        ADD   r1, r1, #&0000a000
    918 ;        AND   r2, r13, r0                      ; mask with discr. mask
    919 ;        CMP   r2, r1                           ; is it a StrongARM ?
    920  
    921         ; switch off MMU, IDcache and WB and branch to physical code !!
    922         CMP r14, #0
    923         EQUD %00011110000100010000111100010000 ; MRCNE cp15, 0, r0, c1, c0, 0 ; read control register
    924         BICNE r0, r0, #&3F                     ; clear only known bits please !
    925         MOVEQ r0, #0                           ; ARM6/7 only have these
    926         ORR r0, r0, #%0001110000
    927         ;             RSB1DPWCAM
    928         MOV r13, r0                            ; save this value in r13
    929         MOV r1, #0
    930         CMP r14, #0
    931         EQUD %11101110000000010000111100010000 ; MCR cp15, 0, r0, c1, c0, 0 ; write control register
    932         EQUD %00011110000001110001111100010101 ; MCRNE cp15, 0, r1, c7, c5, 0 ; write 0 in v4 MMU disable
    933         MOV pc, r9                             ; call rest of code in physical mem ... not flat
    934 
    935       .physical_start_address%
    936         ; should now be running in physical space
    937         ; this relocate code can be heavyly optimised ... but it is used only once ... and is fast enough
    938         ; relocate kernel (physical to physical) + debug in screenmemory
    939         MOV  r5, r10                           ; load PC relative r5 = startreloc table
    940         LDR  r6, [r5], #4                      ; r4 = number of relocated pages
    941       .loop_relocate_pages%
    942         LDR  r2, [r5], #4                      ; r2 = from address
    943         LDR  r3, [r5], #4                      ; r3 = to address
    944         LDR  r7, [r5], #4                      ; r7 = number of bytes to travel
    945         MOV  r1, #0                            ; r1 = offset in page
    946       .loop_one_page%
    947         LDRB r0, [r2, r1]
    948         STRB r0, [r3, r1]
    949         ADD  r1, r1, #1
    950         CMP  r1, r7                            ; all bytes copied ?
    951         BNE loop_one_page%
    952         SUBS r6, r6, #1
    953         BNE loop_relocate_pages%
    954 
    955         ; switch over to the new L1 pages
    956 
    957         ; disable clockswitching for SA110  (WHY?)
    958         MOV r0,  #0                            ; write 0
    959         CMP r14, #0                            ; check v4 .. or SA110 specific ?
    960         EQUD %00011110000011110000111101010010 ; MCRNE cp15, 0, r0, c15, c2, 2 ; from Linux loader
    961 
    962         ; flush ID cache
    963         MOV r0,  #0
    964         CMP r14, #0
    965         EQUD %00001110000001110000111100010000 ; MCREQ cp15, 0, r0, c7, c0, 0 ; flush v3 ID cache
    966         EQUD %00011110000001110000111100010111 ; MCRNE cp15, 0, r0, c7, c7, 0 ; flush v4 ID cache
    967 
    968         ; drain WB (v4)
    969         MOV r0,  #0
    970         CMP r14, #0
    971         EQUD %00011110000001110000111110011010 ; MCRNE cp15, 0, r0, c7, c10, 4; drain WB v4 from Linux loader
    972 
    973         ; flush TLB
    974         EQUD %11101110000001010000111100010000 ; MCR cp15, 0, r0, c5, c0, 0 ; flush v3 TLB
    975 
    976         ; set new TLB address
    977         MOV r0, r11
    978         EQUD %11101110000000100000111100010000 ; MCR cp15, 0, r0, c2, c0, 0 ; write TLB base
    979  
    980         ; switch on MMU, IDcache and WB and keep on running (flat *translated*)
    981         ; in r13 last written value
    982         ORR r0, r13, #%0001111101
    983         ;              RSB1DPWCAM
    984         ORR r0, r0,  #%1000000000
    985         CMP r14, #0
    986         EQUD %11101110000000010000111100010000 ; MCR cp15, 0, r0, c1, c0, 0 ; write control register
    987         MOV r0, r0                             ; flat
    988         MOV r0, r0                             ; flat
    989         ; not flat anymore ... but it doesnt matter
    990     ]
    991     IF extradebug% THEN
    992       [OPT opt%
    993         MOV r6, #videomem_start%
    994         MOV r7, #videomem_pages% * nbpp%
    995         MOV r5, #KERNEL_BASE
    996         .loop_testing%
    997           LDR r0, [r5], #4
    998           STR r0, [r6], #4
    999           SUBS r7, r7, #4
   1000         BNE loop_testing%
   1001        ]
   1002      ENDIF
   1003      [OPT opt%
   1004         ; call kernel in new virtual space ... start()
   1005 
   1006         MOV  r0, r8
   1007         MOV  pc, r12
   1008     ]
   1009   NEXT
   1010 ENDPROC
   1011 
   1012 
   1013 DEF FNblock_vaddr(pagenr%)
   1014 =!(memoryblock% + pagenr%*12 + 4)
   1015 
   1016 
   1017 DEF FNblock_paddr(pagenr%)
   1018 =!(memoryblock% + pagenr%*12 + 8)
   1019 
   1020 
   1021 DEF PROCget_memory_map
   1022   PRINT '"Getting actual memory mapping ";
   1023   FOR pg%=0 TO totalpages%-1
   1024     pos% = memoryblock% + 12*pg%
   1025     pos%!0  = 0
   1026     pos%!4  = (firstpage% + pg%) * nbpp%
   1027     pos%!8  = 0
   1028     REM force paging in this page in RO4
   1029     IF (pg% MOD 5)=0 THEN PROCtwirl
   1030     !(pos%!4) = 0: REM PROCbzero(pos%!4, nbpp%)
   1031   NEXT
   1032   PRINT ;" "
   1033  
   1034   os_memory_GIVEN_LOG_ADDR   = &200
   1035   os_memory_RETURN_PAGE_NO   = &800
   1036   os_memory_RETURN_PHYS_ADDR = &2000
   1037   SYS "OS_Memory", os_memory_GIVEN_LOG_ADDR+os_memory_RETURN_PAGE_NO+os_memory_RETURN_PHYS_ADDR, memoryblock%, totalpages%
   1038  
   1039   PROCsort_memory_map(memoryblock%, totalpages%)
   1040  
   1041   REM Get first DRAM index
   1042   PRINT '"Found memory blocks ";
   1043   first_mapped_DRAM_index%=-1
   1044   pg% = 0
   1045   WHILE pg%<totalpages%
   1046     addr% = !(memoryblock% + pg%*12 + 8)
   1047     PRINT "[";"0x";~addr%;
   1048     num_seq_pag%=0
   1049     WHILE (!(memoryblock% + pg%*12 + 12 + 8) - addr%)=nbpp%
   1050       IF first_mapped_DRAM_index%<0 AND (addr%>=DRAM_addr%(0)) THEN first_mapped_DRAM_index% = pg%
   1051       num_seq_pag%+=1
   1052       pg%+=1
   1053       addr% = !(memoryblock% + pg%*12 + 8)
   1054     ENDWHILE
   1055     PRINT;"-0x";~(!(memoryblock% + pg%*12 + 8) + nbpp%-1);"]";
   1056     PRINT ;"  ";
   1057     pg%+=1
   1058   ENDWHILE
   1059   PRINT'
   1060   IF extradebug% THEN PRINT '"First DRAM index found at index ";first_mapped_DRAM_index%;" DRAM_addr%(0)=0x";~DRAM_addr%(0)
   1061   IF first_mapped_DRAM_index%<0 THEN ERROR EXT 1, "No (S)DRAM mapped in this program (weird) ... increase Wimpslot!"
   1062 ENDPROC
   1063 
   1064 
   1065 DEF PROCget_memory_configuration
   1066   REM Get memory distribution
   1067   PRINT "Getting memory configuration ";
   1068   DIM DRAM_addr%(MAX_DRAMBANKS), DRAM_pages%(MAX_DRAMBANKS)
   1069   DIM VRAM_addr%(MAX_VRAMBANKS), VRAM_pages%(MAX_VRAMBANKS)
   1070   DIM memorytable% memorytablesize%
   1071   SYS "OS_Memory", 7, memorytable% : REM read table
   1072   dramblocks% = 0: vramblocks% = 0: currentpages% = 0: currentadr% = 0
   1073   currentpage% = -1: loop%=0
   1074   WHILE loop% < memorytablesize%*2
   1075     page% = memorytable%!(loop% DIV 2)
   1076     IF loop% MOD 2 THEN page% = page% >> 4
   1077     page% = page% AND &07
   1078     IF page% <> currentpage% THEN
   1079       IF currentpage% = 1 THEN
   1080         DRAM_addr%(dramblocks%) = currentaddr% * nbpp%
   1081         DRAM_pages%(dramblocks%) = currentpages%
   1082         dramblocks% +=1
   1083       ENDIF
   1084       IF currentpage%=2 THEN
   1085         VRAM_addr%(vramblocks%) = currentaddr% * nbpp%
   1086         VRAM_pages%(vramblocks%) = currentpages%
   1087         vramblocks% +=1
   1088        ENDIF
   1089       currentpage% = page%
   1090       currentaddr% = loop%
   1091       currentpages% = 0
   1092     ENDIF
   1093     currentpages% += 64
   1094     loop% += 64
   1095     PROCtwirl
   1096   ENDWHILE
   1097  
   1098   IF emulateDRAMsize% > 0 THEN
   1099     REM emulate HACK
   1100     DRAM0% = DRAM_addr%(0)
   1101     DRAM_addr%() = 0
   1102     DRAM_pages%() = 0
   1103     DRAM_addr%(0) = DRAM0%
   1104     DRAM_pages%(0) = (emulateDRAMsize%*1024*1024)/nbpp%
   1105     dramblocks% = 1
   1106     REM END HACK
   1107   ENDIF
   1108 
   1109   REM find top of DRAM pages
   1110   I%=8: WHILE (I%>=0) AND DRAM_addr%(I%)=0: I%-=1: ENDWHILE
   1111 
   1112   IF I%>=0 THEN top_drambank% = I% ELSE ERROR EXT 0, "Reality check: No DRAM banks??"
   1113   top_physdram% = DRAM_addr%(top_drambank%) + DRAM_pages%(top_drambank%)*nbpp%
   1114 
   1115   PRINT " "
   1116   PRINT'
   1117  
   1118   REM Emulate VRAM by reporting different memory sizes
   1119   REM XXX assumption : no VRAM => screen is located in bottom DRAM; leave it there
   1120   IF (VRAM_pages%(0)=0) OR emulateVRAM% THEN
   1121     mapped_screenmemory% = 1024*1024 : REM Max allowed on RiscPC
   1122     videomem_start% = DRAM_addr%(0)
   1123     videomem_pages% = mapped_screenmemory% DIV nbpp%
   1124     display_size%   = FNvdu_var(150) AND NOT(nbpp%-1)
   1125     DRAM_addr%(0)  += videomem_pages% * nbpp%
   1126     DRAM_pages%(0) -= videomem_pages%
   1127   ELSE
   1128     mapped_screenmemory% = 0
   1129     videomem_start% = VRAM_addr%(0)
   1130     videomem_pages% = VRAM_pages%(0)
   1131     display_size%   = videomem_pages% * nbpp%
   1132   ENDIF
   1133  
   1134   IF mapped_screenmemory%>0 THEN PRINT "Used 1st Mb of DRAM at 0x";RIGHT$("00000000"+STR$~videomem_start%,8);" for video memory"
   1135 
   1136   totaldrampages% = 0
   1137   FOR I%=0 TO dramblocks%-1
   1138     totaldrampages% += DRAM_pages%(I%)
   1139     PRINT "Found ";
   1140     IF (DRAM_addr%(I%) >= SDRAM_ADDR_START%) PRINT ;"SDRAM"; ELSE PRINT ;" DRAM";
   1141     PRINT " (";I%;") at 0x";RIGHT$("00000000"+STR$~DRAM_addr%(I%),8);" for ";,DRAM_pages%(I%)*nbpp%/1024;" k"
   1142   NEXT
   1143 
   1144   totalvrampages% = 0
   1145   FOR I%=0 TO vramblocks%-1
   1146     totalvrampages% += VRAM_pages%(I%)
   1147     PRINT "Found  VRAM (";I%;") at 0x";RIGHT$("00000000"+STR$~VRAM_addr%(I%),8);" for ";,VRAM_pages%(I%)*nbpp%/1024;" k"
   1148   NEXT
   1149  
   1150   kernel_phys_start% = DRAM_addr%(0)
   1151  
   1152   REM Expirimental Kinetic support
   1153   IF INSTR(args$, "kinetic")>0 THEN
   1154     REM The Kinetic card has SDRAM on the processor module ... first fix is to only use this memory
   1155     REM for VRAM emulation and only pass it through as buffer memory for the DRAM is the only one
   1156     REM with DMA capabilities.
   1157  
   1158     PRINT ''"Kinetic support asked ... ";
   1159  
   1160     REM find SDRAM start... DRAM is under 512 Mb, SDRAM is above it
   1161     first_SDRAM% = -1
   1162     FOR I%=0 TO MAX_DRAMBANKS
   1163       IF (DRAM_addr%(I%) >= SDRAM_ADDR_START%) AND (first_SDRAM%<0) THEN first_SDRAM% = I%
   1164     NEXT
   1165     IF first_SDRAM% >= 0 THEN
   1166       PRINT ;"granted"
   1167       REM put kernel pointer to the first SDRAM module and update DRAM reporting (yeah ...more clear than fast)
   1168       FOR I%=0 TO first_SDRAM%-1
   1169         PRINT "Moving DRAM at 0x";RIGHT$("00000000"+STR$~DRAM_addr%(I%),8);" for ";,DRAM_pages%(I%)*nbpp%/1024;" k"
   1170         REM save this block
   1171         DRAM_addr% = DRAM_addr%(I%): DRAM_pages% = DRAM_pages%(I%)
   1172         REM move everything down
   1173         FOR J%=I% TO MAX_DRAMBANKS-1
   1174           DRAM_addr%(J%) = DRAM_addr%(J%+1): DRAM_pages%(J%) = DRAM_pages%(J%+1)
   1175         NEXT
   1176         DRAM_addr%(MAX_DRAMBANKS) = 0: DRAM_pages%(MAX_DRAMBANKS) = 0
   1177         REM fill in the moved block at the top of the structure
   1178         DRAM_addr%(dramblocks%-1) = DRAM_addr%: DRAM_pages%(dramblocks%-1) = DRAM_pages%
   1179       NEXT
   1180       REM XXX kernel is loaded per definition in dram[0]
   1181       first_SDRAM% = 0
   1182       kernel_phys_start% = DRAM_addr%(first_SDRAM%)
   1183     ELSE
   1184       PRINT ;"ignored; no SDRAM found"
   1185     ENDIF
   1186     PRINT
   1187   ENDIF
   1188 ENDPROC
   1189 
   1190 
   1191 DEF PROCsort_memory_map(memoryblock%, totalpages%)
   1192   LOCAL out%, in%, outp%, inp%
   1193 
   1194   DIM code% 1024
   1195   FOR opt%=0 TO 2 STEP 2
   1196     P%=code%
   1197     [OPT opt%
   1198      .sortit%
   1199           STMFD r13!, {r0-r12}
   1200           ; R0  = A% = memory block%
   1201           ; R1  = B% = totalpages%
   1202           ; r2  = out%
   1203           ; r3  = inp%
   1204           ; R12 = limit r3
   1205           SUB r2, r1, #2
   1206      .loop_outer%
   1207           MOV r3, r0
   1208           MOV r4, #12
   1209           MLA r12, r2, r4, r0
   1210      .loop_inner%
   1211           LDR r4, [r3, #8]
   1212           LDR r5, [r3, #20]
   1213           CMP r4, r5
   1214           BLT not_bigger%
   1215             LDMIA r3, {r6, r7, r8}
   1216             ADD r4, r3, #12
   1217             LDMIA r4, {r9, r10, r11}
   1218             STMIA r3, {r9, r10, r11}
   1219             STMIA r4, {r6, r7, r8}
   1220      .not_bigger%
   1221           ADD r3, r3, #12
   1222           CMP r3, r12
   1223           BLE loop_inner%
   1224           SUBS r2, r2, #1
   1225           BPL loop_outer%
   1226           LDMFD r13!, {r0-r12}
   1227           MOV pc, r14
   1228   ]
   1229   NEXT
   1230 
   1231   A% = memoryblock%
   1232   B% = totalpages%
   1233   CALL sortit%
   1234 
   1235 ENDPROC
   1236 
   1237 
   1238 DEF PROCcenter(line$)
   1239   PRINT STRING$((width%-LEN(line$))/2, " ");line$
   1240 ENDPROC
   1241 
   1242 
   1243 DEF PROCbzero(addr%, len%)
   1244   LOCAL a%
   1245   FOR a% = 0 TO len%-4 STEP 4
   1246     addr%!a% = 0
   1247   NEXT
   1248 ENDPROC
   1249 
   1250 
   1251 DEF PROCcopy(dest%, src%, len%)
   1252   LOCAL a%
   1253   FOR a% = 0 TO len%-4 STEP 4
   1254     dest%!a% = src%!a%
   1255   NEXT
   1256 ENDPROC
   1257 
   1258 
   1259 DEF PROCtwirl
   1260   PRINT MID$("|/-\", twirl%+1, 1)+CHR$(8);
   1261   twirl% += 1
   1262   twirl% = twirl% MOD 4
   1263 ENDPROC
   1264 
   1265 
   1266 DEF FNvdu_var(var%)
   1267   LOCAL b%
   1268   DIM b% 7
   1269   b%!0 = var%
   1270   b%!4 = -1
   1271   SYS "OS_ReadVduVariables", b%, b%
   1272 = b%!0
   1273 
   1274 
   1275 DEF FNroundup(val%, size%)
   1276 =val% + (size% - 1) AND NOT (size% - 1)
   1277 
   1278 
   1279 DEF FNtolower(name$)
   1280   LOCAL A$, Ch$, i%
   1281   FOR i%=1 TO LEN(name$)
   1282     Ch$ = LEFT$(name$,1)
   1283     IF Ch$>="A" AND Ch$<="Z" THEN
   1284       A$ += CHR$(ASC(Ch$)+ASC("a")-ASC("A"))
   1285     ELSE
   1286       A$ += Ch$
   1287     ENDIF
   1288     name$ = MID$(name$, 2)
   1289   NEXT
   1290 = A$
   1291 
   1292 DEF FNawaitkey(timeout%)
   1293   LOCAL i%, i$, c%
   1294   REM Flush keyboard buffer first
   1295   REPEAT UNTIL INKEY(0) = -1
   1296   FOR i% = timeout% TO 1 STEP -1
   1297     i$ = STR$(i%)
   1298     PRINT ; i% STRING$(LEN(i$), CHR$(8));
   1299     c% = INKEY(100)
   1300     IF c% <> -1 THEN
   1301       PRINT
   1302       = c%
   1303     ENDIF
   1304   NEXT
   1305   PRINT "0"
   1306 = 0
   1307