;----------------------------------------------------------------- ; 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 , 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 _ (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