;;; -*- Mode:LISP; Package:LISP-INTERNALS; Base:10; Readtable:CL -*- ;; User provides a piece of code which is in two parts, each of which ;; resides on one page (probably using up less than half a page) ;; This code will be written using defafuns which can jump between ;; each other, finally jumping to a constant location, the copy routine. ;; The copy routine will work from an image of the code in low memory ;; and copy it to two pages at offsets which are different and change ;; each time the routine is called. All the other virtual pages should ;; map to a page of all halt instructions. The unused instructions on ;; the copied pages are halt instuctions. Questions: We need to make a type of defafun which is an alignment within a page. Defafuns need to provide us with program length. The user program must guarantee that it does not use A6-A15 ever. These are reserved for the copy program so that we can both call and jump to the user program. We do not handle dispatch instructions. To do this, the relocator will need to be smarter. Set Up. Memory layout Page 0 Trap code Copy code Page 2 User1 Page 3 User2 Page 4 Halt instructions. Remaining pages are possible candidates for copying to. ;these are 32 bit nubus byte addresses (defconst min-phys-adr xxx) (defconst max-phys-adr xxx) (defconst phys-adr-1 xxx) (defconst phys-adr-2 xxx) (defconst inst-block-size-in-bytes (* 16. 1024.)) (defconst map-page-size-in-bytes 4096.) ;initial map has pages 0-4 mapped to low five pages of phys mem, and mapped to ;low five pages of instruction and data space. last page is filled with halt instructions ;phys-page-1 is set to phys page after halt pages ;a15 is pointer to base of memory table (defafun march-copier () ;;a0 = 0 means first user function; a0 = 1 means second move-loop (movei a0 0) select-loop ;;select new physical location ;;read current phys adr for function (movei vma #.phys-adr-1) (alu add vma a0) ;first or second pass (alu l+r vma-start-read-no-transport vma a15) (nop) (movei a14 #.(+ inst-block-size-in-bytes 2)) ;compute new phys address based on old one (alu l+r a14 a14 md) (move a13 a14) ;;split offset from rest of adr (movei a1 #.(- inst-block-size-in-bytes 1)) (alu and a13 a1) ;tenative offset (alu not-r a1 a1 a1) (alu and a14 a1) ;tenative base ;;see if this is the last page by adding ;;the maximum size, and comparing with the max address (movei a1 #.inst-block-size-in-bytes) (alu add a1 a1 a14) (movei vma #.max-phys-adr) (alu l+r vma-start-read-no-transport vma a15) (nop) ;;it's ok for this to be a signed test, since either both addresses will be ;;on the nubus (negative) or in local memory (positive) (alu sub nop a1 md) (test br-less-than) (branch page-ok ()) (movei vma #.min-phys-adr) (alu l+r vma-start-read-no-transport vma a15) (nop) (move a14 md) page-ok (move nop a0) (test br-equal) (branch page-ok-1) ;;this is the second pass, must not select same page as first pass (movei vma #.phys-adr-1) (alu l+r vma-start-read-no-transport vma a15) (nop) (alu sub nop a14 md) (test br-equal) (branch select-loop) ;if collision, just try again page-ok-1 ;;see if the offset is too large, and would cause the function to cross a block boundary (movei vma #.length-1) (alu add vma vma a0) ;first or second pass (alu l+r vma-start-read-no-transport vma a15) (nop) (alu add a12 md md) ;double to get length in 32 bit words ;;a12 is function length in bytes (alu add a12 a12 a13) ;add in the tenative offset (movei a11 #.inst-block-size-in-bytes) (alu sub nop a12 a11) (test br-less-than) (branch off-ok ()) (movei a13 0) off-ok ;;now a14 is address of base of physical page and a13 is offset ;;store updated phys adr (alu add md a14 a13) ;combine base and offset (movei vma #.phys-adr-1) (alu add vma a0) (alu add vma-start-write vma a15) (nop) ;;select virtual page (movei vma #.user-virtual-1) (alu add vma vma a0) ;first or second pass (alu l+r vma-start-read-no-transport vma a15) (nop) (move a12 md) (movei a1 #.(/ inst-block-size-in-bytes 4)) (alu add a12 a12 a1) (test br-not-equal) ;if new page number is zero, then we wrapped, skip to 16'th page (branch virt-ok) (movei a12 #.(+ (ash 1 25.) (* 16. 1024.))) virt-ok ;;a12 is base of virtual page to use ;;write out target virtual address (move md a12) (movei vma #.user-virtual-1) (alu add vma a0) (alu l+r vma-start-write vma a15) ;;fill in 4 map entries ;;read map location zero to get permission bits (movei vma 0) (nop) (nop) (nop) (move a11 memory-map) (alu and a11 a11 #xff) (alu add a10 a14 a11) ;phys base address + permission bits (movei a1 #.map-page-size-in-bytes) (movei a2 #.(/ map-page-size-in-bytes 4)) (move vma a12) ;base virtual page (nop) (nop) (nop) (move memory-map a10) (nop) (nop) (nop) (alu add vma vma a2) ;skip by a map page worth of words (alu add a10 a10 a1) ;skip by a map page worth of bytes (nop) (nop) (nop) (move memory-map a10) (nop) (nop) (nop) (alu add vma vma a2) ;skip by a map page worth of words (alu add a10 a10 a1) ;skip by a map page worth of bytes (nop) (nop) (nop) (move memory-map a10) (nop) (nop) (nop) (alu add vma vma a2) ;skip by a map page worth of words (alu add a10 a10 a1) ;skip by a map page worth of bytes (nop) (nop) (nop) (move memory-map a10) (nop) (nop) (nop) ;;store halts (move vma a12) ;base virtual page (movei a0 #.(/ inst-block-size-in-bytes 4)) (alu add a0 a0 vma) ;end marker (movei md #xffffffff) ;will act as halt instruction store-halt-loop (move vma-start-write vma) (nop) (alu l+1 vma vma vma) (alu sub vma a0) (test br-not-equal) (branch store-halt-loop ()) ;;increment a0 and go back for second function (alu nop a0) (test br-not-equal) (branch do-relocate) (alu l+1 a0 a0 a0) (jump select-loop) do-relocte ...relocate... ...flush icache... (movei vma #.user-virtual-1) (alu add vma-start-read-no-transport vma a15) (nop) ;;call user program ;;convert virtual address to PC, already has 25'th bit set (alu-field field-extract-r vma ignore md (byte 24. -1)) (nop) (dispatch open-call) ;;increment pass counter (movei vma #.pass-counter) (alu add vma-start-read-no-transport vma a15) (nop) (alu l+1 md md md) (move vma-start-write vma) (nop) ;;unmap user pages ;;get map entry for halt page (movei vma #.(ash halt-page 10.)) (nop) (nop) (nop) (move a1 memory-map) (movei a0 0) (movei a2 #.(/ map-page-size-in-bytes 4)) finish-loop (movei vma #.user-virutal-1) (alu add vma a0) (alu add vma-start-read-no-transport vma a15) (nop) (move vma md) (nop) (nop) (nop) (move memory-map a1) (alu add vma vma a2) (nop) (nop) (nop) (move memory-map a1) (alu add vma vma a2) (nop) (nop) (nop) (move memory-map a1) (alu add vma vma a2) (nop) (nop) (nop) (move memory-map a1) (alu nop a0) (test br-not-equal) (jump move-loop) (alu l+1 a0 a0 a0) (jump finish-loop) ) begin Loop select two new physical pages select two new virtual pages Map virtual pages to the physical pages Fill the virtual pages with halt bit (using the function boundary marker) select two new offsets in the pages Copy each of the instructions Relocate the jump instructions scan function looking for conditional jump opcode, add offset to low 12 bits also, scan function looking for calls/long jumps to other function and fix them Jump to the first Copied user function ... Map the used virtual pages back to the halt page. Loop. (alu-field field-exract-r a14 ignore a14 (byte w o))