// 860204 last edited jcgs on m42 // m42!/usr/users/jcgs/misc/prog/orion/mandelbrot.m // // Orion op-code definition for mandelbrot mapping // *I register.m *I opcodes.m *I trapcodes.m // EXTERNAL trap,wcache // /////////////////// //// registers //// /////////////////// // // some registers have double uses // here are the uses in "outer loops": pointer = R0 // temporary pointer to memory stepsize = R1 // pixel increment value for co-ordinates npix = R2 // number of pixels across square xleft = R3 // leftmargin x value xcount = R4 // x counter (in pixels) ycount = R5 // y counter (in pixels) // and here are the uses in "inner loops": zx = R0 zy = R1 ax = R2 ay = R3 work = R4 count = R5 // countdown register // these don't get thus re-used, they communicate between inner and outer sofar = R6 // byte values so far for this set of four points cox = R7 // x co-ordinate coy = R8 // y co-ordinate // /////////////////// //// constants //// /////////////////// // ourfour = (4 << 26) >> 24 // 4 in fixpoint, scaled for Orion const load maxits = 250 // start value for countdown mandelbrot = custom1 // /////////////////////////////// //// outer code for opcode //// /////////////////////////////// // ENTRY umode+mandelbrot restartablemandelbrot: // // come here: // at start of calculations // on restart after memory/interrupt fixup // // wants on stack: // TOS: name description nature // -0 pointer memory pointer variable // -1 cox x-co-ordinate variable // -2 coy y-co-ordinate variable // -3 xcount pixels across this line so far variable // -4 ycount pixels down so far variable // -5 stepsize step from one point in plane to next constant // -6 npix length of square side constant // -7 xleft left margin for flyback constant // // first look for interrupts CJP NINT,memprod // no interrupts, look at memory CONT DZ BR,interrupt OR QREG // interrupt, trap to system interrupted: CJP EV,memprod ZA OR A=psw // unless interruptable mode set CJP NLC,trap // system handler for interrupts CONT // now look at our memory location to force it into core; it shouldn't // be possible to lose it during this instruction! (but I've still // coded as if it is) // we can join here by jumping from the end of the previous iteration // if it found no interrupt active memprod: LDCT earlyfixup DZ CSH OR RAMF B=pointer LVAR CONT TB LBR ADDR // we are using TOS as the VA CJS WFLT,wcache WR // ask "Is it OK to write here?" CONT LOCK // from now on, we know that the location to be written to SHOULD be in core // place prefetch *OVER* TOS CONT INCCA // CA=TOS+1 CONT ZA OR A=ir0 ALU CWR INCCA // CA=TOS+2 CONT ZA OR A=ir1 ALU CWR DECCA // CA=TOS+1 CONT DECCA // CA=TOS+0 CONT DECCA // drop mem pointer from stack // CA=TOS-1 // pop cox,coy,stepsize,npix,xleft, then raise stack pointer over the // ones that don't change; it is then ready to push back the changed // values at the end of this iteration CONT DECCA // CA=TOS-2 CONT DZ CSH OR RAMF B=cox DECCA // CA=TOS-3 CONT DZ CSH OR RAMF B=coy DECCA // CA=TOS-4 CONT DZ CSH OR RAMF B=xcount DECCA // CA=TOS-5 CONT DZ CSH OR RAMF B=ycount DECCA // CA=TOS-6 CONT DZ CSH OR RAMF B=stepsize DECCA // CA=TOS-7 CONT DZ CSH OR RAMF B=npix INCCA // CA=TOS-6 CONT DZ CSH OR RAMF B=xleft INCCA // CA=TOS-5 // all stack values now read; set work to 4*stepsize CONT ZA OR RAMU A=stepsize B=work INCCA // CA=TOS-4 CONT ZB OR RAMU A=work B=work // now check whether at end of row CONT DA BR,4 ADD RAMF A=xcount B=xcount CJP S,points AB SUBS CIN A=xcount B=npix // and check for end of screen (these two jumps won't really occur together) CJP NS,done AB SUBS CIN A=ycount B=npix // if we get here, flyback to left margin CONT ZA OR RAMF A=xleft B=cox CONT AB ADD RAMF A=stepsize B=coy CONT ZB ADD CIN RAMF B=ycount CONT ZB AND RAMF B=xcount // now write back all changed things // then calculate a clump of points, incrementing cox after each one points: // stepsize will be scrambled during actual calculations // so save it in an unusual place CONT ZA OR A=stepsize ALU LBR CONT ZA OR A=ycount ALU CWR INCCA // CA=TOS-3 CONT ZA OR A=xcount ALU CWR INCCA // CA=TOS-2 CONT ZA OR A=coy ALU CWR INCCA // CA=TOS-1 CONT AB ADD A=cox B=work ALU CWR INCCA // allow for increments // CA=TOS+0 CONT ZA ADD CIN A=pointer ALU CWR // save incremented address // The following register changes will now occur // ax (=npix) scrambled // ay (=xleft) scrambled // zx (=pointer) scrambled // zy (=stepsize) scrambled // work (=xcount) scrambled // count (=ycount) incremental result (in top byte) // sofar accumulative result // cox incremented // coy preserved CJS mandelbrotpoint CONT CJS mandelbrotpoint DA BUS ADD RAMF A=cox B=cox CONT CJS mandelbrotpoint DA BUS ADD RAMF A=cox B=cox CONT CJS mandelbrotpoint DA BUS ADD RAMF A=cox B=cox CONT // last increment of column CONT DA BUS ADD RAMF A=cox B=cox // use address before that on top of stack to write the data CONT DZ CSH SUBS LVAR CONT TB LBR ADDR CJS WFLT,wcache ALU ZA OR A=sofar LBR WR // this should never happen, paging was forced at top of instruction: LDCT latefixup LOCK // take one of two routes to the top, according to interrupt status CJP NINT,memprod CONT CONT INCCA CONT INCCA CONT DZ CSH OR RAMF B=ir0 LDIR DECCA CJP interrupted DZ CSH OR RAMF B=ir1 DECCA CONT DZ BR,interrupt OR QREG // end of main outer loop // //////////////////// //// late fixup //// //////////////////// // // code for the write operation to fix things up to restart if for // some reason the fixup at the top of the instruction reneged // this should not happen latefixup: // reconstruct prefetch buffer CONT INCCA // CA=TOS+1 CONT INCCA // CA=TOS+2 CONT DZ CSH OR RAMF B=ir1 DECCA // CA=TOS+1 CONT DZ CSH OR RAMF B=ir0 LDIR DECCA // CA=TOS+0 CONT DECCA // CA=TOS-1 // now read registers in: CONT DZ CSH OR RAMF B=pointer DECCA // CA=TOS-2 CONT DZ CSH OR RAMF B=cox DECCA // CA=TOS-3 CONT DZ CSH OR RAMF B=coy DECCA // CA=TOS-4 CONT DZ CSH OR RAMF B=xcount DECCA // CA=TOS-5 CONT DZ CSH OR RAMF B=ycount DECCA // CA=TOS-6 CONT DZ CSH OR RAMF B=stepsize DECCA // CA=TOS-7 CONT DZ CSH OR RAMF B=npix INCCA // CA=TOS-6 CONT DZ CSH OR RAMF B=xleft INCCA // CA=TOS-5 // four pixelsworth in work CONT ZA OR RAMU A=stepsize B=work INCCA // CA=TOS-4 CONT ZB OR RAMU B=work // recalculate them CJP Z,backline ZA OR A=xcount // take jump if have just wrapped round CONT ZB SUBR RAMF B=pointer // previous location anyway CJP restore AB SUBR CIN RAMF A=stepsize B=cox // left four pixels CONT DA BR,4 SUBR CIN RAMF A=xcount B=xcount backline: CONT AB SUBR CIN RAMF A=stepsize B=coy CONT ZB SUBR RAMF B=ycount CONT ZA SUBR RAMF A=npix B=xcount CONT ZA OR A=npix QREG LDCT 14 ZA AND RAMQD ZERO B=cox MUL RPCT $ AB ADD RAMQD TC MUL A=stepsize B=cox S6 CONT AB ADD RAMQD TC MUL A=stepsize B=cox S6 CONT AB ADD RAMQD TC MUL A=stepsize B=cox S6 CONT AB SUBR CIN RAMQD TC A=stepsize B=cox S6 CONT AB ADD RAMF A=xleft B=cox restore: // now write values back to stack CONT ZA OR A=ycount ALU CWR INCCA // CA=TOS-3 CONT ZA OR A=xcount ALU CWR INCCA // CA=TOS-2 CONT ZA OR A=coy ALU CWR INCCA // CA=TOS-1 CRTN ZA OR A=cox ALU CWR INCCA // CA=TOS+0 CONT ZA OR A=pointer ALU CWR /////// end of fixup code // ///////////////////// //// early fixup //// ///////////////////// // earlyfixup: CRTN CONT // /////////////////////////////////////////// //// ending code for whole calculation //// /////////////////////////////////////////// // // it is slightly different from the normal 'next instruction' stuff, // because of not having kept the instruction prefetch registers intact done: CONT DZ CAIR SHR2 RAMF B=work // CA=TOS-4 CONT DA BR,6 ADD A=work LDCA // CA=TOS+2 CONT DECCA // CA=TOS+1 CONT DZ CSH OR RAMF B=ir1 // read from TOS+2 CONT DZ CSH SHR1 OR RAMF B=ir0 LDIR // read from TOS+1 CONT DZ CAIR SHR2 RAMF B=work // drop all parameters from stack CONT DA BR,9 SUBR CIN A=work LDCA // CA=TOS-8 CJV DA BR,8 SUBR CIN RAMF A=sp B=sp CONT //// end of the ending code // //////////////////////////////////// //// subroutine mandelbrotpoint //// //////////////////////////////////// // // wants registers cox and coy set up on call // leaves its result in top byte of count, // also shifting sofar down one byte // and placing the result in the top byte of sofar // // *** commented out for now, to test things out // mandelbrotpoint: CONT DZ BR,maxits OR RAMF B=count PUSH F ZB AND RAMF B=zx CONT ZB AND RAMF B=zy // main loop begins here // // ax := zx * zx CONT ZA OR QREG A=zx LDCT 14 ZA AND RAMQD ZERO B=work MUL RPCT $ AB ADD RAMQD TC MUL A=zx B=work S6 CONT AB ADD RAMQD TC MUL A=zx B=work S6 CONT AB ADD RAMQD TC MUL A=zx B=work S6 CONT AB SUBR CIN RAMQD TC A=zx B=work S6 ASIN // new value for ax now in Q(lo),work(hi) // rotate it all left 6 bits then copy Q to ax reg CONT ZB OR RAMQU DROT B=work ASIN CONT ZB OR RAMQU DROT B=work ASIN CONT ZB OR RAMQU DROT B=work ASIN CONT ZB OR RAMQU DROT B=work ASIN CONT ZB OR RAMQU DROT B=work ASIN CONT ZB OR RAMQU DROT B=work CONT ZQ OR RAMF B=ax // // ay := zy * zy CONT ZA OR QREG A=zy LDCT 14 ZA AND RAMQD ZERO B=work MUL RPCT $ AB ADD RAMQD TC MUL A=zy B=work S6 CONT AB ADD RAMQD TC MUL A=zy B=work S6 CONT AB ADD RAMQD TC MUL A=zy B=work S6 CONT AB SUBR CIN RAMQD TC A=zy B=work S6 ASIN // new value for ay now in Q(lo),work(hi) // rotate it all left 6 bits then copy Q to ay reg CONT ZB OR RAMQU DROT B=work ASIN CONT ZB OR RAMQU DROT B=work ASIN CONT ZB OR RAMQU DROT B=work ASIN CONT ZB OR RAMQU DROT B=work ASIN CONT ZB OR RAMQU DROT B=work ASIN CONT ZB OR RAMQU DROT B=work CONT ZQ OR RAMF B=ay // // if ax+ay>4 then return CONT DA BR,ourfour SHL3 SUBR CIN RAMF A=ax B=work CJPP NS,pointdone AB ADD A=ay B=work CONT // // count-:=1; if count=0 then return CJPP Z,pointdone ZB SUBR RAMF B=count CONT // // zy := 2*zx*zx+y CONT ZA OR QREG A=zx LDCT 14 ZA AND RAMQD ZERO B=work MUL RPCT $ AB ADD RAMQD TC MUL A=zy B=work S6 CONT AB ADD RAMQD TC MUL A=zy B=work S6 CONT AB ADD RAMQD TC MUL A=zy B=work S6 CONT AB SUBR CIN RAMQD TC A=zy B=work S6 // we want this normalized then doubled, so rotate // the doubleword left 7 bits then take topword from Q CONT ZB OR RAMQU DROT B=work ASIN CONT ZB OR RAMQU DROT B=work ASIN CONT ZB OR RAMQU DROT B=work ASIN CONT ZB OR RAMQU DROT B=work ASIN CONT ZB OR RAMQU DROT B=work ASIN CONT ZB OR RAMQU DROT B=work ASIN CONT ZB OR RAMQU DROT B=work CONT ZQ OR RAMF B=zy CONT AB ADD RAMF A=coy B=zy // // zx := ax -ay +x CONT ZA OR RAMA A=ax B=zx LOOP F AB SUBR CIN RAMF A=ay B=zx CONT AB ADD RAMF A=cox B=zx // end of calculating this point // joint count to values already in sofar // put most recent (rightmost on picture) at top of word, to // suit the Orion's byte-addressing scheme pointdone: CONT DZ ALU SHR1 OR RAMA A=sofar B=sofar CRTN DZ ALU SHL3 OR RAMA A=count B=count CONT AB OR RAMF A=count B=sofar // ////////////////////////////// //// subroutine testpoint //// ////////////////////////////// // // this is a test routine, it draws a stripy pattern // // wants registers cox and coy set up on call // leaves its result in count, also shifting sofar down one byte // and placing the result in the top byte of sofar // mandelbrotpoint: CRTN CONT ZA OR RAMF A=coy B=count CONT AB ADD RAMF A=cox B=count CONT DZ ALU SHR1 OR RAMA A=sofar B=sofar CRTN DA ALU SHL3 OR RAMA A=count B=count CONT AB OR RAMF A=count B=sofar // // end of testpoint // end of file