! Virtual memory management, ! Bus error handling, ! Address translation fault handling, ! Page fault handling. %option "-low-nons-nocheck-nodiag-nostack" %include "mouse:nmouse.inc-nolist" %externalintegerfnspec stoi(%string(255)s) %constinteger - lbpp=10, bpp=1<maxslot u == mmu0[nextslot>>5]; u_dp = nextslot&31 s = u_tdo; u_ssr = 0 ppd == activedesc(nextslot) activedesc(nextslot) == nil %unless ppd==nil %start exqueue(ppd_q) %if s&4=0 %then enqueue(ppd_q,cold) %else enqueue(ppd_q,hot) %finish u_asn = currentprocess_asn u_asm = mode&16_40!16_BF u_lam <- 16_ffff<<(lbpp-8) u_lba = fa>>8 u_pba = phy u_sr = mode&3 clash check(u_ldo) %end %conststring - ipa = "Invalid address (bus error)", iva = "Invalid address (not readable)", wpv = "Invalid address (not writeable)" %own- %record(ptifm)%name pti, %record(ptfm)%name pt, %record(ptefm)%name pte, %record(ppdfm)%name ppd, %integer retries=0,rfa *otsr #16_700 *movem.l d0-d7/a0-a6,-(sp) a4 = gla; d4 = 0 %if 1#ssw&7#2 %or currentprocess==nil %start rompstr("*Fatal bus error ") romphex4(ssw); rompsym(' '); romphex(fa) rompstr(" at "); romphex4(sr); rompsym(' ') romphex(pc); rompsym(' '); romphex4(fw) rompstr(" (no process)") %if currentprocess==nil; rompsym(nl) %cycle; %repeat %finish flags = mmu0_gsr ! %if flags&64#0 %start ! rompstr("*Double MMU fault "); romphex2(mmu0_gsr); rompsym(' ') ! romphex4(ssw); rompsym(' '); romphex(fa); rompsym(nl) ! %finish %if flags&128=0 %start {no MMU fault indicated rfa = fa retries = retries+1 fatal(ipa) %if retries>=100 mmu0_gsr = 0 %else ! %if retries>0 %start ! rompstr("*Spurious bus error at "); romphex(rfa) ! rompstr(" resolved") ! %unless retries=1 %start ! rompstr(" after "); romphex2(retries); rompstr(" attempts") ! %finish ! rompsym(nl) ! retries = 0 ! %finish flags = mmu0_lsr!mmu1_lsr mmu0_gsr = 0 fatal(wpv) %if flags&16_F0#16_A0 {Not USA: assume WV} pti == currentprocess_pti *clr.b pti {get rid of ASN part} %cycle %unless pti==nil %start pt == pti_pt(fa>>(lbpp+lppt)&(tps-1)) %unless pt==nil %start pte == pt_pte(fa>>lbpp&(ppt-1)) %if pte_pba<0 %start new desc(fa,pte_mode,pte_pba) %exit %finish %if pte_pba>0 %start ppd == pte_ppd new desc(fa,ppd_mode,ppd_pba) activedesc(nextslot) == ppd %exit %finish %finish %finish fatal(iva) %if pti==gpti pti == gpti %repeat %finish *movem.l (sp)+,d0-d7/a0-a6 *rte %end %systemroutine map page(%integer log,phy,mode,%record(ptifm)%name index) %record(ptfm)%name pt %record(ptefm)%name pte %integer page,table page = log>>lbpp; table = page>>lppt pt == index_pt(table) %if pt==nil %start pt == new(pt); pt = 0; index_pt(table) == pt %finish pte == pt_pte(page&(ppt-1)) pte_pba = phy>>8 pte_mode = mode!128 %end %routine map range(%integer from,to,mode,%record(ptifm)%name index) %integer ad = from %while ad>16) {[SR=0;PC;FW=0]} push(size[3]{caller's A4};a1;a0;d1;d0) push(a6;addr(newpoa);usp;a3;a2;d7;d6;d5;d4;d3;d2) newprocess_ssp = ssp movetosr(16_2000) mmu0_ast(1)_asn = currentprocess_asn&127 movetosr(16_700) enqueue(newprocess_header,newprocess_runqueue_header) movetosr(0) mmu0_ast(1)_asn = currentprocess_asn %result == newprocess %end %begin %integer i,min=freebot>>lbpp+1,max=freetop>>lbpp-1 %record(ppdfm)%array ppd(min:max) %routine premap(%integer n,mode,as,log) ! Set up a transparently mapped descriptor in MMU0. ! Use slot N, with MODE either READONLY or READWRITE. ! AS specifies both ASM and ASN, LOG specifies both LAM and LBA. %register(a0)%record(mmufm)%name u == mmu0 u_dp = n {select} u_ssr = 0 {invalidate} u_sr = mode; u_asm = as>>8; u_asn = as u_lam = log>>16; u_lba = log; u_pba = log clash check(u_ldo) %end ! At reset, desc 0 will have ASM/ASN 16_FF00, which we wish to ! change to 16_8000, so that any ASN less than 128 will enjoy ! unrestricted transparent address mapping. ! In order to achieve this without getting a clash, we temporarily ! set up desc 1 for transparent mapping using a different ASN. premap(1,readwrite,16_FFFF,0) mmu0_ast(1)_asn = 16_FF mmu0_ast(2)_asn = 16_FF premap(0,readwrite,16_8000,0) mmu0_ast(1)_asn = 0 mmu0_ast(2)_asn = 0 premap(1, readonly,16_8080,16_ffc00000) premap(2,readwrite,16_c0c0,16_ff808000) premap(3,readwrite,16_8080,16_fc00e000) premap(4,readwrite,16_c0c0,16_ffff4000) firstslot = 5; nextslot = 5 maxslot = stoi(cliparam) %unless cliparam="" maxslot = 63 %if maxslot>63; maxslot = 3 %if maxslot<3 {{printstring("Using "); write(maxslot,0); printstring(" MMU slots"); newline activedesc=0 setupqueue(cold;hot) gla = a4 *lea buserrorhandler,a0 *move.l a0,berrvec gpti == new(gpti); gpti = 0 map range(0,16_4000,readonly,gpti) map range(16_800000,16_808000,privbit+readwrite,gpti) map range(16_e00000,16_e40000,readwrite,gpti) map range(16_400000,16_400100,privbit+readwrite,gpti) map range(addr(messagepool),addr(messagepool[1]),privbit+readwrite,gpti) map range(addr(objectpool),addr(objectpool[1]),privbit+readonly,gpti) map range(membot,globalcodelimit,readonly,gpti) currentprocess_asn = currentprocess_asn&127 becomeprocess(1000) min = freebot>>lbpp+1 max = freetop>>lbpp-1 %for i = min,1,max %cycle ppd(i) = 0; enqueue(ppd(i)_q,cold) %repeat semaphorewait(nil) {for now} %end