; Handlers written in assembly (to be as fast as possible) for the ; keyboard emulation of Sim. ; Use Tab Size = 8, or the source code might look ugly. section ".data" include "OS.h" xdef NgetchxEmuHandler xdef LowlevelEmuHandler xdef ForcedLowlevelEmuHandler xdef LowLevelKbdPatches xdef LowLevelKbdPatchesNum xdef RemapMatrix xdef OldAddErrorHandler xdef Fake60001B ; number of keys pairs in NgetchxConv[] (see kbdemu.c) NgetchxConvSize equ 6 ; The handler for the ngetchx() emulation. NgetchxEmuHandler: move.l OldRCTable(pc),a0 move.l ngetchx*4(a0),a0 jsr (a0) ; call the AMS routine lea NgetchxConv-2(pc),a0 ; -2 because of the addq.w #2 in the loop moveq #NgetchxConvSize-1,d1 ; -1 because of the dbra \ConvKey: ; search the keycode in the array addq.w #2,a0 cmp.w (a0)+,d0 dbeq.w d1,\ConvKey bne.s \KeyNotFound move.w (a0),d0 ; new keycode \KeyNotFound: rts ; see InstallLowLevelEmu() for details on these variables. ; extern void *LowLevelKbdPatches; LowLevelKbdPatches dc.l 0 ; extern unsigned short LowLevelKbdPatchesNum; LowLevelKbdPatchesNum dc.w 0 ; extern T_REMAP_MATRIX *RemapMatrix; RemapMatrix dc.l 0 REMAP_MATRIX_H equ 10 REMAP_MATRIX_W equ 8 ; The handler for the lowlevel emulation : called when there was a ; move.b $60001B,? in the program. LowlevelEmuHandler: movem.l d0/d1/a0/a1,-(a7) move.w $600018,d0 bsr Generate60001B ; now search which patch it is move.l LowLevelKbdPatches(pc),a0 move.l 16(a7),d0 ; return address subq.l #6,d0 ; but it points to the next instruction move.w LowLevelKbdPatchesNum(pc),d1 subq.w #1,d1 ; it's a dbra \FindMoveToUse: cmp.l (a0)+,d0 beq.s \MoveToUseFound addq.w #2,a0 ; next element in the stack dbra.w d1,\FindMoveToUse ; should not be reached ; move.l ($c8).w,a0 ; move.l ST_helpMsg*4(a0),a0 ; pea UNEXPECTED_STR(pc) ; jsr (a0) ;\Crashed: ; bra.s \Crashed \MoveToUseFound: lea \Exec(pc),a1 ; create the instruction move.w (a0),(a1) ; write the 'move' instruction movem.l (a7)+,d0/d1/a0/a1 \Exec dc.w 0 ; move dc.l Fake60001B ; source rts Fake60001B dc.b 0 ; simulate the port $60001B, that LowlevelEmuHandler ; generates even ; Create the value of $60001B for this calculator, according to the value ; of $600018. ; input : d0.w = value of $600018 ; output : the new value of $60001B in Fake60001B. a1 points to it. ; d0-d1-a0-a1 destroyed. Generate60001B: moveq #-1,d1 ; the bit of $600018 we are testing ; (there will be a addq #1 further) lea Fake60001B(pc),a1 st.b (a1) ; -> no key pressed \SearchBitCleared: addq.w #1,d1 ; next bit lsr.w #1,d0 ; quit the loop when a cleared bcs.s \SearchBitCleared ; bit is found in $600018.w cmp.b #REMAP_MATRIX_H-1,d1 ; out of the rowread matrix ? bhi \Done ; -> there are no keys to test ; Now d1.w is the row to test lsl.w #5,d1 ; * REMAP_MATRIX_W*2*2 : size of a line of RemapMatrix move.l RemapMatrix(pc),a0 ; -> a0 points to the beginning adda.w d1,a0 ; of the row in RemapMatrix moveq #7,d1 \DoKeysinThisRow: move.w (a0)+,$600018 ; the mask of the key to test bne.s \AKeyToTest addq.w #2,a0 ; -> REMAP_KEY_NOT_USED bra.s \OneKeyDone ; Test the next key in the row \AKeyToTest: moveq #6,d0 \WaitHW: dbra.w d0,\WaitHW move.w (a0)+,d0 ; the bit of $60001B to test btst.b d0,$60001B bne.s \OneKeyDone bclr.b d1,(a1) ; the key was pressed. Write it. \OneKeyDone: dbra.w d1,\DoKeysinThisRow \Done rts ; Address Error handler for the lowlevel keyboard scanning emulation in ; forced mode. Called each time $600018 is written to. ; When ForcedLowlevelEmuHandler() is installed, LowlevelEmuHandler() is not ; installed. ForcedLowlevelEmuHandler: ; Has the program crashed or are is it really writting to $600018 ? cmp.l #$600019,2(a7) ; 'access address' in the stack frame beq.s \NoCrash move.l OldAddErrorHandler(pc),-(a7) rts ; call the old handler \NoCrash: move.w #$2700,sr ; no interrupts ; Save all the address registers, because they can be all modified ; (see further) movem.l d0-d1/a0-a6,-(a7) move.w 4*2+4*7+6(a7),d0 ; 'instruction register' in the stack frame move.l 4*2+4*7+10(a7),a0 ; 'program counter' ; place to save the address where $600019 is in the instruction. If ; the instruction is writing with an indirect addressing mode, it ; will stay to 0.l. clr.l -(a7) \SearchInstr: ; search the address of the instruction that caused the error cmp.w -(a0),d0 beq.s \InstrFound cmp.l #$600019,(a0) bne.s \SearchInstr subq.l #1,(a0) ; the real instruction with $600018 move.l a0,(a7) ; save the address bra.s \SearchInstr \InstrFound: ; We need to execute the real instruction to get the new value of ; $600018. ; We do not know the size of the instruction, we must trace it. lea \Return(pc),a2 lea $40024,a1 move.l (a1),-(a7) ; save the vector move.l a2,(a1) ; new vector pea (a0) ; a0 points to the instruction (will be read by 'rte') ; the instruction must be run in the right environnement movem.l 4*3(a7),d0-d1/a0-a6 ; 4 addresses have been pushed ; Now no writing in the registers ! tst.l 4*2(a7) ; $600019 was found ? bne.s \x600019Found ; The instruction is trying to write to $600018 in indirect ; mode. We must find a change the right address register (hoping ; there will only be once...) ; Now no writing in the address registers ! ; Code of cmp.l #$6000018,Ax : % 1011REG1 11111100 ; Substract %10 because of the first addq.b move.b #%10110001-%10,\Cmp600019 ; number of the address register (-1 because of the first addq.b) move.b #-1,AddRegNum \SearchAddReg: addq.b #%10,\Cmp600019 ; REG+1->REG addq.b #1,AddRegNum \Cmp600019: cmp.l #$600019,a0 ; will become a1, then a2, ... bne.s \SearchAddReg ; code of subq.l #1,Ax : %01010011 10001REG, where REG is AddRegNum. or.b #%10001000,AddRegNum move.b AddRegNum(pc),\Subq1Instr+1 nop ; the subq.l must not be preloaded ! \Subq1Instr: subq.l #1,a0 ; the register will contain $600018 \x600019Found: ; The program may try to read something from the stack, so we give ; him the user stack pointer. move.w #$8700,-(a7) ; Trace on, in User mode, ints masked rte ; run it \Return: ; back in supervisor mode, with a new stack frame move.w #$2700,sr ; Trace off addq.w #6,a7 ; remove the stack frame move.w $600018,d0 ; read the value the program has written ; (parameter for Generate60001B) ; The program counter of the stack frame of the address error becomes ; the program counter of the stack frame of Trace, that points to ; the next instruction in the program. We will use it for the rte. move.l -4(a7),4*2+4*2+4*7+10(a7) move.l (a7)+,$40024 ; the old trace vector move.l (a7)+,a0 ; where $600019 was found in the instruction move.l a0,d1 ; or was it an indirect mode ? beq.s \No600019InInstr addq.l #1,(a0) ; rewrite $600019 \No600019InInstr: bsr Generate60001B movem.l (a7)+,d0-d1/a0-a6 ; Remove the supervisor stack frame, but keep the saved PC and SR. addq.w #14-6,a7 rte ; And here were are ! OldAddErrorHandler dc.l 0 AddRegNum dc.b 0