; AltIOUtila.asm -- assembly-language code for AltIO ; Last modified March 14, 1981 2:37 PM .ent MemRead .ent MemWrite .ent MemRMW .ent MemReadBlock32A .ent MemWriteBlock32A .ent MemReadBlock40A .ent MemWriteBlock40A .ent MemZeroA .ent MemReadAbsolute .ent MemWriteAbsolute .ent MemRMWAbsolute .ent MemReadRelative .ent MemWriteRelative .ent MemRMWRelative .ent DisplaceMaxcAdr .ent InputSMI .ent OutputSMI .ent OutputSMIPulse .ent InputSMIErrors .ent OutputSMITest .ent ExecuteMicroInstruction .ent LoadBus .ent ReadBus .ent FindZeroMaxcBit .ent FindOneBit .ent SetOneMaxcBit .ent StartIntervalTimer .ent IncrementMaxcWord .ent AltIOParityHandler .ent parityData .ent AltIOSwatProc .ent USetBLV .ent ImpConvTo32 .ent ImpConvTo36 .ent ImpConvFrom32 .ent ImpConvFrom36 .bext adrMTBS .bext icb ; All the special opcodes defined in the microcode (MaxcAltoCode): setblv = #63000 mfetch = #66000 mstore = #66001 mrmw = #66002 mblks = #66003 mfblk32 = #66004 msblk32 = #66005 mfblk40 = #66006 msblk40 = #66007 convto32 = #70000 convto36 = #70400 convfrom32 = #71000 convfrom36 = #71400 .srel MemRead: .MemRead MemWrite: .MemWrite MemRMW: .MemRMW MemReadBlock32A: .MemReadBlock32A MemWriteBlock32A: .MemWriteBlock32A MemReadBlock40A: .MemReadBlock40A MemWriteBlock40A: .MemWriteBlock40A MemZeroA: .MemZeroA MemReadAbsolute: .MemReadAbsolute MemWriteAbsolute: .MemWriteAbsolute MemRMWAbsolute: .MemRMWAbsolute MemReadRelative: .MemReadRelative MemWriteRelative: .MemWriteRelative MemRMWRelative: .MemRMWRelative DisplaceMaxcAdr: .DisplaceMaxcAdr InputSMI: .InputSMI OutputSMI: .OutputSMI OutputSMIPulse: .OutputSMIPulse InputSMIErrors: .InputSMIErrors OutputSMITest: .OutputSMITest ExecuteMicroInstruction: .ExecuteMicroInstruction LoadBus: .LoadBus ReadBus: .ReadBus FindZeroMaxcBit: .FindZeroMaxcBit FindOneBit: .FindOneBit SetOneMaxcBit: .SetOneMaxcBit StartIntervalTimer: .StartIntervalTimer IncrementMaxcWord: .IncrementMaxcWord AltIOParityHandler: .AltIOParityHandler parityData: .parityData AltIOSwatProc: .AltIOSwatProc USetBLV: .USetBLV ImpConvTo32: .ImpConvTo32 ImpConvTo36: .ImpConvTo36 ImpConvFrom32: .ImpConvFrom32 ImpConvFrom36: .ImpConvFrom36 .nrel ; Procedures implementing Maxc memory operations ; All take the following arguments: ; maxcAdr ; pointer to 2-word Maxc address vector. The top 16 bits ; are in the first word and the bottom 4 bits left-justified ; in the second word. ; maxcData ; pointer to data vector. For single-word operations, this ; is 3 words, with the top 32 bits in the first two words and ; the bottom 8 bits (including the 4 tag bits) in the third. ; For block operations, this is a vector of either 3-word ; or 2-word blocks, depending on whether all 40 bits or only ; the top 32 bits of each Maxc word are being transferred. ; count (block operations only) ; Maxc word count. ; All return an error code upon completion: ; 0 normal ; 1 parity error detected on data bus during read or RMW ; (if RMW, the write was nevertheless completed) ; 2 timed out (>80 microseconds to complete operation) ; 4 interface busy when started (should never happen) ; 10 unimplemented operation ; It is conceivable that more than one of the above errors could ; occur at the same time. ; Block operations update the address vector to contain the Maxc ; address of the first word not transferred (this is true whether ; or not the transfer completes successfully). ; Single-word operations ; MemRead(maxcAdr, maxcData) ; fetches one word from Maxc and puts in data vector. ; MemWrite(maxcAdr, maxcData) ; stores one word from data vector to Maxc. ; MemRMW(maxcAdr, maxcData) ; "or"s the data vector with the Maxc word and puts ; the result both into the data vector and into Maxc. ; Block operations. These procedures should in general be called ; only via the corresponding procedures in AltIOUtilb.bcpl ; (without the "A" suffix). ; MemZeroA(maxcAdr, nil, count) ; zeros the specified number of successive Maxc words. ; MemReadBlock32A(maxcAdr, maxcData, count) ; fetches a block of words from Maxc, putting only ; the top 32 bits in the data vector. ; MemWriteBlock32A(maxcAdr, maxcData, count) ; stores a block of words to Maxc, getting only the ; top 32 bits from the data vector (bottom 8 get ; garbage). ; MemReadBlock40A(maxcAdr, maxcData, count) ; fetches a block of words from Maxc, putting all ; 40 bits in the data vector. ; MemWriteBlock40A(maxcAdr, maxcData, count) ; stores a block of words to Maxc, getting all 40 ; bits from the data vector. .MemRead: mfetch jmp mdone .MemWrite: mstore jmp mdone .MemRMW: mrmw jmp mdone .MemReadBlock32A: sta 3 1 2 lda 3 3 2 ; get count mfblk32 jmp bdone .MemWriteBlock32A: sta 3 1 2 lda 3 3 2 ; get count msblk32 jmp bdone .MemReadBlock40A: sta 3 1 2 lda 3 3 2 ; get count mfblk40 jmp bdone .MemWriteBlock40A: sta 3 1 2 lda 3 3 2 ; get count msblk40 jmp bdone .MemZeroA: sta 3 1 2 jsr .+4 ; make pointer to block of 3 zeroes 0 0 0 mov 3 1 lda 3 3 2 ; get count mblks bdone: lda 3 1 2 mdone: lda 1 c4 ; test for "busy when started" se 0 1 jmp 1 3 ; ok, just return lda 0 c20000 ; reset the memory interface sio lda 0 c4 jmp 1 3 c4: 4 c20000: 20000 ; Higher-level memory operations ; Coded in assembly language to make them faster ; MemReadAbsolute(adr, maxcData) ; Do a memory read at address "adr", given as a 16-bit number .MemReadAbsolute: sta 3 1 2 jsr MemOpAbsolute ; common setup code jmp .MemRead ; desired operation ; MemWriteAbsolute(adr, maxcData) .MemWriteAbsolute: sta 3 1 2 jsr MemOpAbsolute ; common setup code jmp .MemWrite ; desired operation ; MemRMWAbsolute(adr, maxcData) .MemRMWAbsolute: sta 3 1 2 jsr MemOpAbsolute ; common setup code jmp .MemRMW ; desired operation ; Common setup code for absolute operations MemOpAbsolute: sta 3 3 2 ; save return sta 1 2 2 ; preserve maxcData pointer cycle 12. ; low 4 address bits to b0-3 lda 1 2 2 ; recover maxcData pointer sta 0 2 2 ; store low 4 bits of address lda 3 c7777 ; mask high 12 bits and 3 0 lda 3 1 2 ; recover return address sta 0 1 2 ; store high 12 bits in frame inc 2 0 ; use frame+1, +2 as address vector jmp @3 2 ; return to do the operation ; Unfortunately, the "Relative" operations can't be collapsed into ; common code like the "Absolute" ones because we don't have ; enough temporaries. ; MemReadRelative(displacement, maxcData, base) ; Do a memory read at address "displacement" relative to the ; address vector "base", which defaults to adrMTBS. .MemReadRelative: sta 3 1 2 sta 1 2 2 ; preserve maxcData pointer cycle 12. ; low 4 displacement bits to b0-3 lda 1 c170000 ; mask them and 0 1 lda 3 c7777 ; mask high 12 bits and 3 0 lda 3 3 2 ; get base vector sta 0 3 2 ; save high 12 displacement bits lda 0 @1 2 ; get number of arguments movzr# 0 0 snc ; skip if odd (3) lda 3 @lvAdrMTBS ; default to MTBS lda 0 1 3 ; get low 4 bits of base address addz 1 0 szc ; add displacement isz 3 2 ; carry into high displacement lda 1 3 2 ; recover high displacement lda 3 0 3 ; get high 16 bits of base add 3 1 ; add displacement lda 3 1 2 ; recover return address sta 1 1 2 ; store high 16 address bits lda 1 2 2 ; recover maxcData pointer sta 0 2 2 ; store low 4 address bits inc 2 0 ; use frame+1, +2 as address vector jmp .MemRead ; go do the operation ; MemWriteRelative(displacement, maxcData, base) .MemWriteRelative: sta 3 1 2 sta 1 2 2 ; preserve maxcData pointer cycle 12. ; low 4 displacement bits to b0-3 lda 1 c170000 ; mask them and 0 1 lda 3 c7777 ; mask high 12 bits and 3 0 lda 3 3 2 ; get base vector sta 0 3 2 ; save high 12 displacement bits lda 0 @1 2 ; get number of arguments movzr# 0 0 snc ; skip if odd (3) lda 3 @lvAdrMTBS ; default to MTBS lda 0 1 3 ; get low 4 bits of base address addz 1 0 szc ; add displacement isz 3 2 ; carry into high displacement lda 1 3 2 ; recover high displacement lda 3 0 3 ; get high 16 bits of base add 3 1 ; add displacement lda 3 1 2 ; recover return address sta 1 1 2 ; store high 16 address bits lda 1 2 2 ; recover maxcData pointer sta 0 2 2 ; store low 4 address bits inc 2 0 ; use frame+1, +2 as address vector jmp .MemWrite ; go do the operation ; MemRMWRelative(displacement, maxcData, base) .MemRMWRelative: sta 3 1 2 sta 1 2 2 ; preserve maxcData pointer cycle 12. ; low 4 displacement bits to b0-3 lda 1 c170000 ; mask them and 0 1 lda 3 c7777 ; mask high 12 bits and 3 0 lda 3 3 2 ; get base vector sta 0 3 2 ; save high 12 displacement bits lda 0 @1 2 ; get number of arguments movzr# 0 0 snc ; skip if odd (3) lda 3 @lvAdrMTBS ; default to MTBS lda 0 1 3 ; get low 4 bits of base address addz 1 0 szc ; add displacement isz 3 2 ; carry into high displacement lda 1 3 2 ; recover high displacement lda 3 0 3 ; get high 16 bits of base add 3 1 ; add displacement lda 3 1 2 ; recover return address sta 1 1 2 ; store high 16 address bits lda 1 2 2 ; recover maxcData pointer sta 0 2 2 ; store low 4 address bits inc 2 0 ; use frame+1, +2 as address vector jmp .MemRMW ; go do the operation ; DisplaceMaxcAdr(displacement, maxcAdr, base) ; stores in maxcAdr the result of computing displacement relative ; to base, which defaults to adrMTBS. .DisplaceMaxcAdr: sta 3 1 2 sta 1 2 2 ; save maxcAdr cycle 12. ; right-justify high 12 disp bits lda 1 c7777 ; mask them and 0 1 sta 1 @2 2 ; store in maxcAdr!0 lda 1 c170000 ; get low 4 disp bits and 0 1 lda 3 3 2 ; get base vector lda 0 @1 2 ; get number of arguments movzr# 0 0 snc ; skip if odd (3) lda 3 @lvAdrMTBS ; default to MTBS lda 0 1 3 ; get low 4 bits of base address lda 3 0 3 ; get high displacement addz 0 1 szc ; add low base and displacement inc 3 3 ; carry into high base lda 0 @2 2 ; recover high displacement add 3 0 lda 3 2 2 ; store result in maxcAdr vector sta 0 0 3 sta 1 1 3 lda 3 1 2 jmp 1 3 c170000: 170000 c7777: 7777 lvAdrMTBS: adrMTBS ; Miscellaneous procedures ; FindZeroMaxcBit(maxcWord) = bit number or -1 ; Finds the first zero bit in the Maxc word. ; At present, this procedure tests only the first 32 bits. .FindZeroMaxcBit: sta 3 1 2 mov 0 3 lda 0 0 3 ; get first 16 bits com 0 0 szr ; turn zeroes into ones jmp fzmw0 ; found one, go search word lda 0 1 3 ; get second 16 bits com 0 0 szr ; turn zeroes into ones jmp fzmw1 ; found one, go search word mkminusone 0 0 ; none found, return -1 lda 3 1 2 jmp 1 3 fzmw0: jsr .FindOneBit ; found zero in first 16 bits 1 lda 3 1 2 jmp 1 3 fzmw1: jsr .FindOneBit ; found zero in second 16 bits 1 lda 1 d16 add 1 0 lda 3 1 2 jmp 1 3 ; FindOneBit(word) = bit number or -1 ; Finds the first one bit in the 16-bit Alto word .FindOneBit: mov 0 1 snr ; quick check for zero jmp retm1 lda 0 c400 ; test for bits on in left half subz# 0 1 snc ; skip if ge 400 (unsigned) movs 1 1 skp ; no, look in right byte mkzero 0 0 skp ; left byte, start at zero lda 0 d8 ; right byte, start at 8 movzl 1 1 szc ; test a bit jmp 1 3 ; a one, done inc 0 0 ; increment count, try next jmp .-3 retm1: mkminusone 0 0 jmp 1 3 d8: 8. d16: 16. c400: 400 ; SetOneMaxcBit(maxcWord,bit) ; Sets the specified bit number in the Maxc data vector .SetOneMaxcBit: sta 3 1 2 mov 0 3 ; ac3 ← word pointer mkzero 0 0 ; zero out the data vector sta 0 0 3 sta 0 1 3 sta 0 2 3 movzr 1 0 ; compute bit number / 16 movzr 0 0 movzr 0 0 movzr 0 0 add 0 3 ; point to correct 16-bit word subzr 0 0 ; one in bit 0 neg 1 1 ; right cycle (bit number mod 16) cycle 0 sta 0 0 3 ; store the resulting bit lda 3 1 2 jmp 1 3 ; StartIntervalTimer(interval, chanMask) ; Enables the interval timer to interrupt after interval*.595 ; microseconds on the channel(s) specified by chanMask .StartIntervalTimer: sta 1 @itibits ; set channel mask sta 0 2 2 ; save interval rclk ; ac1 ← low part of clock lda 0 2 2 ; add interval add 0 1 lda 0 c177700 ; mask off non-clock stuff and 0 1 sta 1 @ittime ; time at which to interrupt mkone 0 0 ; enable timer, normal mode sit jmp 1 3 c177700: 177700 ittime: 525 ; page 1 locations itibits: 423 ; IncrementMaxcWord(maxcData, increment) ; Adds the 16-bit "increment" to the 36-bit "maxcData" .IncrementMaxcWord: sta 3 1 2 mov 0 3 ; ac3 ← maxcData pointer mov 1 0 ; ac0 ← increment cycle 12. ; left-cycle increment by 12 sta 0 2 2 ; save result lda 1 c170000 ; extract former low-order 4 bits and 1 0 lda 1 2 3 ; get low 4 bits of maxc word addz 0 1 szc ; add increment isz 2 2 ; carry into high part of increment sta 1 2 3 ; store updated low maxc word lda 0 2 2 ; get back cycled increment lda 1 c7777 ; extract high 12 bits and 1 0 lda 1 1 3 ; get middle 16 bits of maxc word addz 0 1 szc ; add increment isz 0 3 ; carry into high maxc word nop sta 1 1 3 ; store updated middle maxc word lda 3 1 2 jmp 1 3 ; Procedures for controlling the System Maintenance Interface. ; The procedures on this page may be called from ; non-interrupt level at any time and at interrupt level iff ; Maxc is running (maxcRunning is true). All others may be called ; only from non-interrupt level and only while Maxc is stopped. ; InputSMI(adr) = value ; Returns the value provided by the SMI input device "adr" .InputSMI: dir sta 0 @adreg lda 0 @inreg jmp smiend ; OutputSMI(adr,value) ; Sends "value" to the SMI output device "adr" .OutputSMI: dir sta 0 @adreg sta 1 @outreg jmp smiend ; OutputSMIPulse(adr,value) ; Same as OutputSMI, but for use when loading memory configuration ; registers only. .OutputSMIPulse: dir sta 0 @adreg sta 1 @outregp smiend: mkzero 1 1 sta 1 @adreg eir jmp 1 3 ; InputSMIErrors() = value ; Reads and resets the SMI error register. .InputSMIErrors: lda 0 @errinf jmp 1 3 ; OutputSMITest(value) ; Sets the SMI test register .OutputSMITest: sta 0 @testreg jmp 1 3 adreg: 177400 inreg: 177401 outregp: 177402 outreg: 177403 errinf: 177404 testreg: 177405 ; Procedures for executing Maxc microinstructions through the SMI. ; Coded in assembly language to make them faster. ; ExecuteMicroInstruction(adr) ; Executes the Maxc microinstruction at adr!0 through adr!3, ; using the control word at adr!4 .ExecuteMicroInstruction: sta 3 1 2 mov 0 3 dir lda 0 smiPIR3 ; PIR3-PIR0 are 214-217 sta 0 @adreg ; load PIR3 lda 1 3 3 sta 1 @outreg inc 0 0 ; load PIR2 sta 0 @adreg lda 1 2 3 sta 1 @outreg inc 0 0 ; load PIR1 sta 0 @adreg lda 1 1 3 sta 1 @outreg inc 0 0 ; load PIR0 sta 0 @adreg lda 1 0 3 sta 1 @outreg lda 0 smiCR ; load control register sta 0 @adreg lda 1 4 3 com 1 1 ; must complement data sta 1 @outreg lda 3 1 2 jmp smiend ; SMI addresses smiCR: 210 smiPIR3: 214 ; LoadBus(maxcData) ; Loads the Maxc bus register with 36 bits of maxcData .LoadBus: sta 3 1 2 mov 0 3 dir lda 0 smiBR2 ; BR2-BR0 are 211-213 sta 0 @adreg ; load BR2 lda 1 2 3 coms 1 1 ; move data to right byte sta 1 @outreg inc 0 0 ; load BR1 sta 0 @adreg lda 1 1 3 com 1 1 ; must complement data sta 1 @outreg inc 0 0 ; load BR0 sta 0 @adreg lda 1 0 3 com 1 1 ; must complement data sta 1 @outreg lda 3 1 2 jmp smiend ; ReadBus(maxcData) ; Reads the 36-bit Maxc bus into maxcData .ReadBus: sta 3 1 2 mov 0 3 dir lda 0 smiB2 ; B2-B0 are 201-203 sta 0 @adreg ; read B2 lda 1 @inreg coms 1 1 ; move data to left byte sta 1 2 3 inc 0 0 ; read B1 sta 0 @adreg lda 1 @inreg com 1 1 ; must complement data sta 1 1 3 inc 0 0 ; read B0 sta 0 @adreg lda 1 @inreg com 1 1 ; must complement data sta 1 0 3 lda 3 1 2 jmp smiend ; SMI addresses smiBR2: 211 smiB2: 201 ; Parity interrupt handler ; Leaves results in parityData vector .AltIOParityHandler: sta 0 save0 ; save emulator state sta 1 save1 sta 3 save3 movr 0 0 sta 0 saveCarry jsr .+1 ; save data left by parity task rregrel: lda 1 offst add 3 1 ; points to last destination word lda 3 cm6 ; 6 words to transfer lda 0 c613 ; starting at 614 blt lda 0 @disp ; save state of display sta 0 saveDisp mkzero 0 0 ; turn it off sta 0 @disp lda 1 @active ; save active channels sta 1 saveActive sta 0 @active ; disable all channels lda 1 dwait lda 0 @disk ; wait for disk and display to stop inc 1 1 snr mov 0 0 szr jmp .-3 sta 0 numErrors ; initialize error count lda 3 endMem ; highest real memory location +1 sta 3 .parityData ; set flag parl1: lda 0 @ww ; get current waiting wakeups movr 0 0 ; turn off parity wakeup movzl 0 0 sta 0 @ww eir ; reenable copying of NWW to WW parl2: mov# 3 3 snr ; see if done jmp parl4 ; yes lda 0 -1 3 ; read a memory word neg 3 3 ; decrement address (done here to com 3 3 ; give error time to "take") lda 1 @ww ; see if parity interrupt pending movr 1 1 snc jmp parl2 ; no dir ; yes, interrupt system back off sta 3 errorAdr ; save address sta 0 errorData ; save contents sta 0 0 3 ; write word back into memory isz numErrors ; increment error count jmp parl1 ; reset WW and keep scanning ; here when done scan parl4: dir lda 0 saveDisp ; restore display sta 0 @disp lda 0 saveActive ; restore active interrupts sta 0 @active lda 0 saveCarry ; restore emulator state movl 0 0 lda 3 save3 lda 1 save1 lda 0 save0 bri ; dismiss interrupt ; AltIOParityHandler (cont'd) ; Data is left in this vector, which must correspond to ; the ParData structure in AltIO.decl .parityData: 0 ; nonzero to report an error rregs: .blk 6 ; 6 words of data saved by parity task numErrors: 0 ; number of errors detected by sweep errorAdr: 0 ; address of bad word errorData: 0 ; contents of bad word ; other stuff save0: 0 save1: 0 save3: 0 saveCarry: 0 offst: rregs+5-rregrel cm6: -6 c613: 613 disp: 420 saveDisp: 0 active: 453 saveActive: 0 dwait: -2000. disk: 521 endMem: 177000 ww: 452 ; Swat context-switching procedure ; Called with 0 when entering Swat and -1 when leaving. .AltIOSwatProc: ; Cause an interval timer interrupt as we leave Swat, since one probably ; occurred while Swat was running, and Swat may have lost it. snz 0 0 ; leaving swat? jmp swatp1 ; entering, do nothing lda 0 @ww ; yes, cause timer interrupt lda 1 @imask com 1 1 and 1 0 adc 1 0 sta 0 @ww ; Reset the Imp interface and drop host ready swatp1: lda 2 @lvICB mkone 0 0 sta 0 0 2 ; icMasterReset lda 0 c3000 ; impControlStatus mov 2 1 sio ; StartIO(impControlStatus, icb) lda 0 c7 ; icHostReadyOff sta 0 0 2 lda 0 c3000 sio ; StartIO(impControlStatus, icb) jmp 1 3 imask: 423 lvICB: icb c3000: 3000 c7: 7 ; USetBLV(blv) ; Sets the Boot Locus Vector to blv, in preparation for silent boot. .USetBLV: setblv jmp 1 3 ; The following procedures, implemented mostly in microcode, ; convert between the Imp and Maxc2 data formats. ; The Imp format is just a continuous bit stream, packed into 16-bit words. ; The Maxc format is the same continuous bit stream, but packed either ; 32 or 36 bits per Maxc word and stored in Alto memory in the correct ; format for (36-bit) Maxc memory operations. ; All procedures assume that the first 72 bits of a message (Imp and ; Host leader) have been dealt with by the software. Thus, transfers start ; with the 73rd bit, which happens to fall in the middle of an Alto word ; in Imp format. ; In the descriptions of block formats: ; 00, 01, etc., are names for 4-bit nibbles. ; ** is a nibble whose value is undefined (source) or may be ; clobbered arbitrarily (destination). ; XX is a nibble that must be preserved (destination). ; -- is a zero nibble. ; ImpConvTo32(dest, source, count) ; Converts Imp message to Maxc 32-bit format. ; It is assumed that the first 8 bits of the source block have ; already been consumed. ; dest = first destination address ; source = first source address ; count = Maxc word count ; Source block format: ; ** ** 00 01 <- dest ; 02 03 04 05 ; 06 07 ** ** ; Destination block format: ; 00 01 02 03 <- source ; 04 05 06 07 ; ** ** ** ** .ImpConvTo32: sta 3 1 2 lda 3 3 2 convto32 lda 3 1 2 jmp 1 3 ; ImpConvTo36(dest, source, count) ; Converts Imp message to Maxc 36-bit format. ; It is assumed that the first 8 bits of the source block have ; already been consumed. ; dest = first destination address ; source = first source address ; count = Maxc word count ; Source block format: ; ** ** 00 01 <- dest ; 02 03 04 05 ; 06 07 08 09 ; 10 11 12 13 ; 14 15 16 17 ; 18 19 20 21 ; 22 23 24 25 ; 26 27 28 29 ; 30 31 32 33 ; 34 35 ** ** ; Destination block format: ; 00 01 02 03 <- source ; 04 05 06 07 ; 08 ** ** ** ; 09 10 11 12 ; 13 14 15 16 ; 17 ** ** ** ; 18 19 20 21 ; 22 23 24 25 ; 26 ** ** ** ; 27 28 29 30 ; 31 32 33 34 ; 35 ** ** ** .ImpConvTo36: sta 3 1 2 lda 3 3 2 convto36 lda 3 1 2 jmp 1 3 ; ImpConvFrom32(dest, source, count) ; Converts Imp message from Maxc 32-bit format. ; It is assumed that the first 8 bits of the destination block have ; already been filled. ; dest = first destination address ; source = first source address ; count = Maxc word count ; Note: The last 8 bits of the block are not transferred. The caller ; must specify a Maxc word count one larger than the number of Maxc ; words actually present, and provide 2 words of extra space in the ; destination block. ; Source block format: ; 00 01 02 03 <- dest ; 04 05 06 07 ; ** ** ** ** ; Destination block format: ; XX XX 00 01 <- source ; 02 03 04 05 ; 06 07 ** ** .ImpConvFrom32: sta 3 1 2 lda 3 3 2 convfrom32 lda 3 1 2 jmp 1 3 ; ImpConvFrom36(dest, source, count) ; Converts Imp message from Maxc 36-bit format. ; It is assumed that the first 8 bits of the destination block have ; already been filled. ; dest = first destination address ; source = first source address ; count = Maxc word count ; Note: The last few bits of the block are not transferred. The caller ; must specify a Maxc word count one larger than the number of Maxc ; words actually present, and provide 3 words of extra space in the ; destination block. ; Source block format: ; 00 01 02 03 <- dest ; 04 05 06 07 ; 08 ** ** ** ; 09 10 11 12 ; 13 14 15 16 ; 17 ** ** ** ; 18 19 20 21 ; 22 23 24 25 ; 26 ** ** ** ; 27 28 29 30 ; 31 32 33 34 ; 35 ** ** ** ; Destination block format: ; XX XX 00 01 <- source ; 02 03 04 05 ; 06 07 08 09 ; 10 11 12 13 ; 14 15 16 17 ; 18 19 20 21 ; 22 23 24 25 ; 26 27 28 29 ; 30 31 32 33 ; 34 35 ** ** .ImpConvFrom36: sta 3 1 2 lda 3 3 2 convfrom36 lda 3 1 2 jmp 1 3 .end