;----------------------------------------------------------------- ; XMesaRAM.Mu - Overflow XMesa microcode from ROM1 ; version 5, compatible with main microcode >=39 ; Last modified by Johnsson - February 1, 1980 1:51 PM ;----------------------------------------------------------------- ; Separate assembly requires... #Mesab.mu; ;----------------------------------------------------------------- ; Entry Point Definitions: ; ; The definitions below must correspond to those in Mesab. ;----------------------------------------------------------------- %1,1777,20,GoToROM; must match ramMgo %1,1777,402,BLTintpend,BLTloop; BLTloop must match ramBLTloop %3,1777,404,BLTnoint,BLTint,BLTLnoint,BLTLint; BLTint must match ramBLTint %1,1777,410,Overflow; must correspond to ramOverflow ;----------------------------------------------------------------- ; BITBLT linkage: ; An additional constraint peculiar to the BITBLT microcode is that ; the high-order 7 bits of the return address be 1's. Hence, ; the recommended values are: ; no ROM1 extant or emulator in ROM1 => BITBLTret = 177577B ; ROM1 extant and emulator in RAM => BITBLTret = 177175B ;----------------------------------------------------------------- $ROMBITBLT $L004124,0,0; BITBLT routine address (124B) in ROM0 $BITBLTret $177175; (may be even or odd) ; The third value in the following pre-def must be: (BITBLTret AND 777B)-1 %1,1777,174,BITBLTintr,BITBLTdone; return addresses from BITBLT in ROM0 ;----------------------------------------------------------------- ; Overflow instruction dispatch ;----------------------------------------------------------------- !17,20,RR,BLTL,WR,MISC,DADD,DSUB,DCOMP,DUCOMP,BITBLT,,,,,,,; dispatched in ROM1 GoToROM: T←ONE, SWMODE; smash G to disable gp←T, :romMgo; optimization on initial entry ;----------------------------------------------------------------- ; D o u b l e - P r e c i s i o n A r i t h m e t i c ;----------------------------------------------------------------- ; !1,1,DSUBsub; shake B/A dispatch !3,4,DAStail,,,DCOMPr; returns from DSUBsub !1,1,Dsetstkp; shake ALUCY dispatch !1,1,Setstkp; shake IDISP from BLTnoint Overflow: :RR; dispatch pending ; TASK pending for doubles ;----------------------------------------------------------------- ; DADD - add two double-word quantities, assuming: ; stack contains precisely 4 elements ;----------------------------------------------------------------- ; !1,1,DADDx; shake B/A dispatch !1,2,DADDnocarry,DADDcarry; DADD: T←stk2, :DADDx; T:low bits of right operand DADDx: L←stk0+T; L:low half of sum stk0←L, ALUCY; stash, test carry T←stk3, :DADDnocarry; T:high bits of right operand DADDnocarry: L←stk1+T, :DASCtail; L:high half of sum DADDcarry: L←stk1+T+1, :DASCtail; L:high half of sum ;----------------------------------------------------------------- ; DSUB - subtract two double-word quantities, assuming: ; stack contains precisely 4 elements ;----------------------------------------------------------------- DSUB: IR←msr0, :DSUBsub; ;----------------------------------------------------------------- ; Double-precision subtract subroutine ;----------------------------------------------------------------- !1,2,DSUBborrow,DSUBnoborrow; !7,1,DSUBx; shake IR← dispatch DSUBsub: T←stk2, :DSUBx; T:low bits of right operand DSUBx: L←stk0-T; L:low half of difference stk0←L, ALUCY; borrow = ~carry T←stk3, :DSUBborrow; T:high bits of right operand DSUBborrow: L←stk1-T-1, IDISP, :DASCtail; L:high half of difference DSUBnoborrow: L←stk1-T, IDISP, :DASCtail; L:high half of difference ;----------------------------------------------------------------- ; Common exit code ;----------------------------------------------------------------- DASCtail: stk1←L, ALUCY, :DAStail; carry used by double compares DAStail: T←2, :Dsetstkp; adjust stack pointer Dsetstkp: L←stkp-T, SWMODE, :Setstkp; Setstkp: stkp←L, :romnext; 'next' has proper SWMODE bit ;----------------------------------------------------------------- ; DCOMP - compare two long integers, assuming: ; stack contains precisely 4 elements ; result left on stack is -1, 0, or +1 (single-precision) ;----------------------------------------------------------------- ; !1,1,DCOMPxa; shake B/A dispatch !10,1,DCOMPxb; shake IR← dispatch !1,2,DCOMPnocarry,DCOMPcarry; !1,2,DCOMPgtr,DCOMPequal; DCOMP: IR←T←100000, :DCOMPxa; IR←msr0, must shake dispatch DCOMPxa: L←stk1+T, :DCOMPxb; scale left operand DCOMPxb: stk1←L; L←stk3+T, TASK; scale right operand stk3←L, :DSUBsub; do DSUB, return to DCOMPr DCOMPr: T←stk0, :DCOMPnocarry; L: stk1, ALUCY pending DCOMPnocarry: L←0-1, BUS=0, :DCOMPsetT; left opnd < right opnd DCOMPcarry: L←M OR T; L: stk0 OR stk1 SH=0; DCOMPsetT: T←3, :DCOMPgtr; T: amount to adjust stack DCOMPgtr: L←0+1, :DCOMPequal; left opnd > right opnd DCOMPequal: stk0←L, :Dsetstkp; stash result ;----------------------------------------------------------------- ; DUCOMP - compare two long cardinals, assuming: ; stack contains precisely 4 elements ; result left on stack is -1, 0, or +1 (single-precision) ; (i.e. result = sign(stk1,,stk0 DSUB stk3,,stk2) ) ;----------------------------------------------------------------- DUCOMP: IR←sr3, :DSUBsub; returns to DCOMPr ;----------------------------------------------------------------- ; E m u l a t o r A c c e s s ;----------------------------------------------------------------- ;----------------------------------------------------------------- ; RR - push <emulator register alpha>, where: ; RR is A-aligned (also ensures no pending branch at entry) ; alpha: 1 => wdc, 2 => XTSreg, 3 => XTPreg, 4 => ATPreg, ; 5 => OTPreg ;----------------------------------------------------------------- !7,10,RR0,RR1,RR2,RR3,RR4,RR5,,; RR: SINK←ib, BUS; dispatch on alpha RR0: L←0, SWMODE, :RR0; (so SH=0 below will branch) RR1: L←wdc, SH=0, :romUntail; will go to pushTA RR2: L←XTSreg, SH=0, :romUntail; will go to pushTA RR3: L←XTPreg, SH=0, :romUntail; will go to pushTA RR4: L←ATPreg, SH=0, :romUntail; will go to pushTA RR5: L←OTPreg, SH=0, :romUntail; will go to pushTA ;----------------------------------------------------------------- ; WR - emulator register alpha ← <TOS> (popped), where: ; WR is A-aligned (also ensures no pending branch at entry) ; alpha: 1 => wdc, 2 => XTSreg ;----------------------------------------------------------------- !7,10,WR0,WR1,WR2,,,,,; ; WR: L←ret3, TASK, :Xpopsub; performed in ROM WR: SINK←ib, BUS; dispatch on alpha WR0: SWMODE, :WR0; WR1: wdc←L, :romnextA; WR2: XTSreg←L, :romnextA; ;----------------------------------------------------------------- ; BLT - block transfer ; assumes stack has precisely three elements: ; stk0 - address of first word to read ; stk1 - count of words to move ; stk2 - address of first word to write ; the instruction is interruptible and leaves a state suitable ; for re-execution if an interrupt must be honored. ;----------------------------------------------------------------- !1,2,BLTmore,BLTdone; !1,2,BLTsource,BLTCsource; !1,2,BLTeven,BLTodd; !1,1,BLTintx; shake branch from BLTloop ; Entry sequence in ROM1; actual entry is at BLTloop ;BLT: stk7←L, SWMODE, :BLTx; stk7=0 <=> branch pending ;BLTx: IR←msr0, :ramBLTloop; IR← is harmless BLTloop: L←T←stk1-1, BUS=0, :BLTnoint; BLTnoint: stk1←L, L←BUS AND ~T, IDISP, :BLTmore; L←0 on last iteration (value ; on bus is irrelevant, since T ; will be -1). IDISP on last ; cycle requires that Setstkp ; be odd. BLTmore: T←cp, :BLTsource; BLTsource: MAR←stk0, :BLTupdate; start data source fetch BLTCsource: XMAR←stk0+T, :BLTupdate; start code source fetch BLTupdate: L←stk0+1; stk0←L; update source pointer L←stk2+1; T←MD; source data MAR←stk2; start dest. write stk2←L, L←T; update dest. pointer SINK←NWW, BUS=0, TASK; check pending interrupts MD←M, :BLTintpend; loop or check further BLTintpend: SINK←wdc, BUS=0, :BLTloop; check if interrupts enabled ; Must take an interrupt if here (via BLT or BITBLT) BLTint: SINK←stk7, BUS=0, :BLTintx; test even/odd pc BLTintx: L←mpc-1, :BLTeven; prepare to back up BLTeven: mpc←L, L←0, :BLTodd; even - back up pc, clear ib BLTodd: ib←L, SWMODE; odd - set ib non-zero :romIntstop; ; BLT completed BLTdone: SINK←stk7, BUS=0, SWMODE, :Setstkp; stk7=0 => return to 'nextA' ;----------------------------------------------------------------- ; BLTL - block transfer (long pointers) ; assumes stack has precisely five words: ; stk0, stk1 - address of first word to read ; stk2 - count of words to move ; stk3, stk4 - address of first word to write ; the instruction is interruptible and leaves a state suitable ; for re-execution if an interrupt must be honored. ; the following are used as temporaries (here and BITBLT): ; stk7 - saved B/A flag from instruction dispatch ; stk6 - saved value of emulator bank register ;----------------------------------------------------------------- !7,1,BLTLsetBR; shake BUS=0 and IR← !7,1,BLTLsetBRx; shake IR← !7,10,BLTLret0,BLTLret1,BLTLret2,BBret3,BBret4,,,; !1,2,BLTLintpend,BLTLloop; !1,2,BLTLmore,BLTLdone; ;!1,2,BLTLnoint,BLTLint; appears above ; Note: ROM1 code does stk7←L BLTL: MAR←BankReg; access bank register T←stk1; high source bits L←stk1+T; L: high source *2 temp←L LSH 1, IR←msr0; temp: high source *4; L←MD, TASK; L: old bank register stk6←L; stk6: stashed register T←stk4; T: high dest bits T←3.T, :BLTLsetBR; (would like to avoid this) ; returns to BLTLret0 BLTLloop: L←T←stk2-1, BUS=0, :BLTLnoint; decrement count, test done BLTLnoint: stk2←L, :BLTLmore; T: -1 the last time BLTLmore: MAR←stk0; fetch source word L←stk0+1; bump source pointer stk0←L; L←stk3+1; bump destination pointer T←MD; XMAR←stk3; initiate store stk3←L, L←T; L: data SINK←NWW, BUS=0, TASK; check for possible interrupt BLTLret0: MD←M, :BLTLintpend; stash data BLTLintpend: SINK←wdc, BUS=0, :BLTLloop; check if enabled BLTLint: IR←sr2, :BLTLsetBR; restore bank before interrupt BLTLret2: MD←stk6, :BLTint; BLTint shakes branch BLTLdone: IR←sr1, :BLTLsetBR; restore bank before exit BLTLret1: MD←stk6, L←stk6 AND NOT T, :BLTdone; BLTdone shakes branch, L←0 BLTLsetBR: MAR←BankReg, :BLTLsetBRx; BLTLsetBRx: L←temp OR T, IDISP; (used by BLTLret0 only) SINK←0, BUS=0, :BLTLret0; force branch for BLTLret0 ; others must shake ;----------------------------------------------------------------- ; BITBLT - do BITBLT using ROM0 subroutine ; If BITBLT A-aligned, B byte will be ignored ; temporaries (in addition to BLTL): ; stk5 - 0=>short BITBLT, 2=>long BITBLT ; stk4 - holds original value of first word of table ; (can't do BITBLT with long bit on!) ;----------------------------------------------------------------- ; from ROM ;!1,1,BITBLTx; shake B/A dispatch ;BITBLT: stk7←L, :BITBLTx; save even/odd across ROM call ;BITBLTx: L←10, SWMODE, :DoRamRWB; !1,2,IntOff,TestLong; !1,2,LongBB,DoBITBLT; also shake SetBR branch %2,3,1,BBshortDone,BBlongDone; $longSourceOffset $21; high bits of source addr $longDestOffset $23; high bits of dest addr BITBLT: L←stk1, TASK; AC1←L; MAR←L←stk0; fetch word for long check AC2←L, L←0; stash descriptor table stk5←L; L←MD, TASK; stk4←L; save first word SINK←wdc, BUS=0; check if Mesa interrupts off T←100000, :IntOff; IntOff: L←NWW OR T; if so, shut off Nova's NWW←L, :TestLong; TestLong: L←stk4 XOR T; complement high bit MAR←stk0, SH<0; prepare to store T←stk0, :LongBB; !7,1,BBx; shake IR←sr3 LongBB: MD←M; high bit off MAR←longSourceOffset+T; high source addr L←longDestOffset+T; taskhole←L; L←T←MD; L←M+T, TASK; temp←L LSH 1; temp*4 MAR←taskhole; high dest addr IR←sr3; for call to BLTLsetBR L←2, :BBx; BBx: stk5←L; T←MD; MAR←BankReg; T←3.T; L←temp OR T; temp←L; L←MD, TASK; old Bank reg stk6←L, :BLTLsetBR; BBret3: MD←temp, :DoBITBLT; DoBITBLT: L←BITBLTret, SWMODE; get return address PC←L, L←0, :ROMBITBLT; L←0 for Alto II ROM0 "feature" BITBLTdone: T←100000; L←NWW AND NOT T; SINK←stk5, BUS; NWW←L, L←T←0, :BBshortDone; BBlongDone: MAR←stk0; restore old word IR←sr4; MD←stk4, :BLTLsetBR; BBret4: MD←stk6, L←T, :BBshortDone; BBshortDone: brkbyte←L, BUS=0, SWMODE, :Setstkp; don't bother to validate stkp BITBLTintr: MAR←stk0; restore old word L←AC1; pick up intermediate state MD←stk4; SINK←stk5, BUS; stk1←L, :BLTint; stash instruction state