bible_documentations/software/notes/g35E_OS02.05.2201_keysc_int...

302 lines
10 KiB
Plaintext

Casio's KEYSC interrupt handler (0xbe0) - OS 02.05.2201 (SH4)
This is the Casio's KEYSC handler documentation part.
The handler is really long and I can not write the entire documentation, but there is
all important part of the handler.
Handler start at: 0x80040c08
First part (1/2): check which type of interruption occur
40c08: 2f c6 mov.l r12,@-r15
40c0a: 2f d6 mov.l r13,@-r15
40c0c: 2f e6 mov.l r14,@-r15
40c0e: 4f 22 sts.l pr,@-r15
40c10: 7f f0 add #-16,r15
40c12: dd 43 mov.l 0x40d20,r13 ! a44b0000
40c14: dc 43 mov.l 0x40d24,r12 ! 8800b268
# Call a sub-routine which will disable KEYSC's interrupt visibility
# (add interrupt mask and set interrupt level at 0, but this is not
# the part that it will remove the KEYSC interrupt flags).
40c16: d2 34 mov.l 0x40ce8,r2 ! 8003f960
40c18: 42 0b jsr @r2
40c1a: 00 09 nop
Sub-routine: 0x8003f960
Goal: Disable KEYSC interrupt visibility.
# Jump into <3f974> sub-routine.
3f960: a0 08 bra 0x3f974
3f962: 00 09 nop
# <3f974> entry !
# Get some addresses and masks.
3f974: d4 78 mov.l 0x3fb58,r4 ! a4080094
3f976: e1 80 mov #-128,r1 ! ffffff80
3f978: 95 5b mov.w 0x3fa32,r5 ! fff
# Add KEYSC interrupt mask using the IMR5 register.
3f97a: 24 10 mov.b r1,@r4
# Disable the KEYSC interrupt (using his interrupt level)
# using the IPRF register.
3f97c: 74 80 add #-128,r4 ! a4080014
3f97e: 62 41 mov.w @r4,r2
3f980: 22 59 and r5,r2
3f982: 00 0b rts
3f984: 24 21 mov.w r2,@r4
First part (2/2): check which type of interruption occur
# Get the content of the KEYSC interrupt controller register and save it.
40c1c: 85 da mov.w @(20,r13),r0 ! a44b0014
# Get the content of <0x8800b268>.
# I don't know what is the purpose of this variable, but that's my interpretation:
# The Casio's KEYSC interrupt configuration enable interrupt when one key is press,
# release and when the key is held down.
# This variable is here to say "If at least one key is already pressed, exit".
# This is explained why Casio skip all the KEYSC handler and just clean the interrupt.
40c1e: 66 c2 mov.l @r12,r6 ! 8800b268
40c20: 26 68 tst r6,r6
40c22: 8d 02 bt.s 0x40c2a
40c24: 6e 03 mov r0,r14
# Jump into <80040dbe> sub-routine.
# This routine will check the <8800b268> (undocumented) Casio's variable.
40c26: a0 ca bra 0x40dbe
40c28: 00 09 nop
# Check the KEYSC interrupt controller.
40c2a: 60 e3 mov r14,r0
40c2c: c8 08 tst #8,r0
40c2e: 8b 01 bf 0x40c34
40c30: a1 fa bra 0x41028
40c32: 00 09 nop
Sub-routine: 0x800040bde
# Check the (undocumented) Casio's variable.
# Sometime, Casio does not clear voluntary the KEYSC interrupt and loop into the handler.
# So this variable is probably used for each loop (?)
# TODO: Write doc.
40dbe: 60 c2 mov.l @r12,r0
40dc0: 88 01 cmp/eq #1,r0
40dc2: 89 01 bt 0x40dc8
40dc4: a0 93 bra 0x40eee
40dc6: 00 09 nop
40dc8: 60 e3 mov r14,r0
40dca: c8 02 tst #2,r0
40dcc: 8b 01 bf 0x40dd2
40dce: a1 2b bra 0x41028
40dd0: 00 09 nop
Second part: KEYSC CASIO SCAN
# This part is really long and not very interesting, so I will not document all the part.
# part 1] - dump the KEYSC
40c34: 61 d1 mov.w @r13,r1
40c36: 2f 11 mov.w r1,@r15
40c38: d6 3b mov.l 0x40d28,r6 ! 8800baa5
40c3a: 85 d1 mov.w @(2,r13),r0
40c3c: 81 f1 mov.w r0,@(2,r15)
40c3e: 85 d2 mov.w @(4,r13),r0
40c40: 81 f2 mov.w r0,@(4,r15)
40c42: 64 60 mov.b @r6,r4
40c44: 85 d3 mov.w @(6,r13),r0
40c46: 81 f3 mov.w r0,@(6,r15)
40c48: 24 48 tst r4,r4
40c4a: 85 d4 mov.w @(8,r13),r0
40c4c: 81 f4 mov.w r0,@(8,r15)
40c4e: 85 d5 mov.w @(10,r13),r0
40c50: 8d 19 bt.s 0x40c86
40c52: 81 f5 mov.w r0,@(10,r15)
# part 2.1] - get key pressed.
# Casio's probably check special characters and set information into internal cache ??? (implausible)
40c54: 60 f1 mov.w @r15,r0
40c56: c8 01 tst #1,r0
40c58: 89 02 bt 0x40c60
40c5a: d6 34 mov.l 0x40d2c,r6 ! 8800baa4
40c5c: e2 01 mov #1,r2
40c5e: 26 20 mov.b r2,@r6
40c60: 85 f4 mov.w @(8,r15),r0
40c62: c8 40 tst #64,r0
40c64: 89 03 bt 0x40c6e
40c66: d6 32 mov.l 0x40d30,r6 ! 8800baa7
40c68: e2 10 mov #16,r2
40c6a: a0 0c bra 0x40c86
40c6c: 26 20 mov.b r2,@r6
40c6e: c8 20 tst #32,r0
40c70: 89 06 bt 0x40c80
40c72: d6 2f mov.l 0x40d30,r6 ! 8800baa7
40c74: 60 60 mov.b @r6,r0
40c76: 88 10 cmp/eq #16,r0
40c78: 8b 05 bf 0x40c86
40c7a: e2 02 mov #2,r2
40c7c: a0 03 bra 0x40c86
40c7e: 26 20 mov.b r2,@r6
40c80: d6 2b mov.l 0x40d30,r6 ! 8800baa7
40c82: e2 01 mov #1,r2
40c84: 26 20 mov.b r2,@r6
# Call sub-routine which whill check column (or row) key ?.
40c86: 65 f3 mov r15,r5
40c88: 64 f3 mov r15,r4
40c8a: bf 5b bsr 0x40b44
40c8c: 75 0c add #12,r5
40c8e: 40 15 cmp/pl r0
40c90: 8d 02 bt.s 0x40c98
40c92: 62 03 mov r0,r2
40c94: a1 c0 bra 0x41018
40c96: 00 09 nop
#### TODO: finish to write documentation ?
Finish the job ! 0x8004101c
# This is the most important part of the handler: clear the KEYSC interrupt flags !
# It the weirdest way to clear interrupt flag...just reload the KEYSC interrupt
# controller by itself. (>_>)
# (Here Casio force the KEYSC interrupt configuration (0x0048)).
#NOTE
# You SHOULD mask ans disable the KEYSC interrupt before reload the
# configuration because if not, the calculator will crash.
# To clear KEYSC's interrupt properly you can directly reload the KEYSC
# configuration into the KEYSC configuration.
# `KEYSC.INTERRUPT = KEYSC.INTERRUPT`
# And the interrupt is correctly cleared !
4101c: e6 48 mov #72,r6
4101e: 60 ec extu.b r14,r0
41020: 46 18 shll8 r6
41022: 20 6b or r6,r0
41024: b0 4f bsr 0x410c6
41026: 81 da mov.w r0,@(20,r13)
# Check KEYSC's interrupt register and check if all keys are released.
# "(r14 & 64) | (r14 & 32) --> 0x66" and this code which indicate that
# the last key has been released.
41028: 60 e3 mov r14,r0
4102a: c9 40 and #64,r0
4102c: 62 03 mov r0,r2
4102e: 60 e3 mov r14,r0
41030: c9 20 and #32,r0
41032: 22 0b or r0,r2
41034: 22 28 tst r2,r2
# If the last key has been released, jump into the last sub-routine <80041044>
# which will restore the KEYSC interruption and exit properly.
#
# NOTE
# I don't know why, but if the sub-routine is involved, Casio do not clear the
# KEYSC interrupt; so I think that they voluntary keep the interrupt flag,
# return to the handler's start and indicate that the last key has been released.
# This is explained why, when we press many key, only the first and last keys
# are printed (?)
41036: 89 05 bt 0x41044
# Clear KEYSC interruption !!!!
# NOTE: Casio force the KEYSC interrupt configuration.
41038: e6 48 mov #72,r6
4103a: 60 ec extu.b r14,r0
4103c: 46 18 shll8 r6
4103e: 20 6b or r6,r0
# Call sub-routine <410c6>
41040: b0 41 bsr 0x410c6
41042: 81 da mov.w r0,@(20,r13)
The last part of the handler
Goal: Enable KEYSC interrupt and restore stack then exit.
# call the <8003f968> function.
41044: d2 60 mov.l 0x411c8,r2 ! 8003f968
41046: 42 0b jsr @r2
41048: 00 09 nop
# Restore stack and exit :D
4104a: 7f 10 add #16,r15
4104c: 4f 26 lds.l @r15+,pr
4104e: 6e f6 mov.l @r15+,r14
41050: 6d f6 mov.l @r15+,r13
41052: 00 0b rts
41054: 6c f6 mov.l @r15+,r12
<8003f968> function !
Goal: Enable KEYSC interrupt and remove interrupt mask
# Jump into <0x3f986>
3f968: a0 0d bra 0x3f986
3f96a: 00 09 nop
# <0x3f986> entry !
# Sub-routine called by many time by the (0xbe0) interrupt.
# Enable the KEYSC interruption (IPRF register).
3f986: d4 75 mov.l 0x3fb5c,r4 ! a4080014
3f988: 97 53 mov.w 0x3fa32,r7 ! fff
3f98a: 92 53 mov.w 0x3fa34,r2 ! d000
3f98c: e5 80 mov #-128,r5
3f98e: 61 41 mov.w @r4,r1
3f990: 21 79 and r7,r1
3f992: 21 2b or r2,r1
3f994: 24 11 mov.w r1,@r4
# clear KEYSC interrupt mask (IMCR5 register).
3f996: d4 72 mov.l 0x3fb60,r4 ! a40800d4
3f998: 00 0b rts
3f99a: 24 50 mov.b r5,@r4
# ...and exit
3f99c: 00 0b rts
3f99e: 00 09 nop
Sub-routine: 0x800410c6
TODO: write documentation.
410c6: d5 46 mov.l 0x411e0,r5 ! 8800b268
410c8: 66 52 mov.l @r5,r6
410ca: 26 68 tst r6,r6
410cc: 89 07 bt 0x410de
410ce: d7 41 mov.l 0x411d4,r7 ! 8800b2a8
410d0: e4 10 mov #16,r4
410d2: d2 44 mov.l 0x411e4,r2 ! 8800b2a4
410d4: d6 34 mov.l 0x411a8,r6 ! 8800b2a0
410d6: 61 72 mov.l @r7,r1
410d8: 22 12 mov.l r1,@r2
410da: a0 07 bra 0x410ec
410dc: 26 40 mov.b r4,@r6
410de: d6 41 mov.l 0x411e4,r6 ! 8800b2a4
410e0: 62 62 mov.l @r6,r2
410e2: 42 15 cmp/pl r2
410e4: 89 02 bt 0x410ec
410e6: d6 30 mov.l 0x411a8,r6 ! 8800b2a0
410e8: e2 00 mov #0,r2
410ea: 26 20 mov.b r2,@r6
410ec: d6 3e mov.l 0x411e8,r6 ! 8800b29c
410ee: e0 14 mov #20,r0
410f0: e2 00 mov #0,r2
410f2: 25 22 mov.l r2,@r5
410f4: 15 21 mov.l r2,@(4,r5)
410f6: 15 22 mov.l r2,@(8,r5)
410f8: 15 23 mov.l r2,@(12,r5)
410fa: 15 24 mov.l r2,@(16,r5)
410fc: 05 24 mov.b r2,@(r0,r5)
410fe: e0 15 mov #21,r0
41100: 05 24 mov.b r2,@(r0,r5)
41102: 00 0b rts
41104: 26 22 mov.l r2,@r6