Getting H.TIMI Interrupt

Page 1/2
| 2

By fpracek

Rookie (25)

fpracek's picture

25-07-2022, 15:02

Hello guys,
I'm trying to develop my first assembly MSX-DOS application after my really first little application in 1986 (the nostalgy wins...).

Actually, my goal is to capture the SHIFT key press action when the user write something on MSX-DOS prompt.

I created this code where after "start" label I rewrite H.TIMI routine for to call my custom "readKeys" routine and this solution works.
Into debug mode I can observe the execution to arrive on my break point on "ld a,(KEYS+6)" row.
The execution do not continue on next instruction "bit 0,a" and I don't understand why. If I try to use step in debug command I lost myself into standard code.

Can you help me to find the issue on my code?

Thanks.

Fausto

; MSX-DOS entry point
BDOS equ #0005

;MSX BIOS CALLS
KEYINT  equ     #0038
KEYS    equ     #FBE5
H_TIMI  equ     #FD9A

; MSX-DOS function codes
STROUT  equ #0009

; START POINT!
        org #100

start:
        di
        ld hl,H_TIMI
        ld de,oldHook
        ld bc,5
        ldir

        ld hl,H_TIMI
        ld de, readKeys
        ld (hl), #C3
        ld (H_TIMI+1), de
        ei
        ret

readKeys:
        ld a,(KEYS+6)
        bit 0,a
        jp z, ShiftKeyPressed
        jp oldHook

ShiftKeyPressed:
        push de
        ld de, message
        ld c, STROUT
        call BDOS
        pop de
        jp oldHook
message:
        db "Key pressed!$"
oldHook:
        db #C9,#C9,#C9,#C9,#C9
; use the label "start" as the entry point
finish:
        end start
Login or register to post comments

By albs_br

Champion (455)

albs_br's picture

25-07-2022, 15:21

Not sure if the cause of the problem is this, but if oldHook is mapped to ROM, it will not be possible to be written by this piece of code:

        ld hl,H_TIMI
        ld de,oldHook
        ld bc,5
        ldir

By MsxKun

Paragon (1112)

MsxKun's picture

25-07-2022, 15:41

When the CPU jumps to H_TIMI, the page 0 is already set into the ROM BIOS, so page 0 on your RAM (with your code) is gone until you're back from the interrupt. So you must move your readkeys routine out of page0. From $4000 above.

By Grauw

Ascended (10634)

Grauw's picture

25-07-2022, 18:05

Safest is to put the handler at an address above C000H (page 3). Because pages 1 and 2 are also not guaranteed to be the main RAM, e.g. Disk ROM could be selected in page 1 when the interrupt occurs.

Alternatively, instead of jumping to your handler directly, you can also do an interslot call from H.TIMI to your handler in page 0: RST 30H (CALLF) followed by the RAM slot and the address. The hooks are exactly 5 bytes long to fit an interslot call.

By fpracek

Rookie (25)

fpracek's picture

26-07-2022, 12:44

Thanks for your help.
I tryed to change my org to 4000h and C000h also, but without changes in application execution results.
I'll try interslot solution, but before I must learn it.

Actually in my machine the memory configuration is this:

slots

By ToriHino

Paladin (806)

ToriHino's picture

26-07-2022, 19:39

You should not just change org (since it has to start at 0100h), but copy the part from readKeys to for example C000h. Also make sure when changing the H_TIMI hook to than no longer use the readKeys label but the actual address you copied it to, otherwise it still tries to call your code in page 0. Same goes by the way for all labels used in the copied code (like ShiftKeyPressed). Depending on your assembler there might be a directive to deal with relocated code, which will fix the labels problem for you. An easy solution is to only use JR instead of JP, since this is already relative, regardless the actual location of the code.

By ducasp

Hero (611)

ducasp's picture

26-07-2022, 22:19

fpracek wrote:

Thanks for your help.
I tryed to change my org to 4000h and C000h also, but without changes in application execution results.
I'll try interslot solution, but before I must learn it.

Actually in my machine the memory configuration is this:

slots

Check this:

https://github.com/ducasp/MSX-Development/blob/master/MSX-SM...

Check from line 468 to 495, probably you do not need to use special high mem memory area to save the old hook call if you are running on ram and can save the old hook address there (to restore in case you are uninstalled), so you probably are better of starting from line 484 and having the 5 bytes memory area address to the old hook in DE. Just make sure the address is on the same page of your hook code, OR, in page 3. GETSLT is defined beginning line 4680 (Courtesy of Konamiman). My HTIM hook code is on line 2046, since you probably are not going to use HIMEM memory but your own memory area on the same page / area of your hook code to save the old hook, a simplified version would be:

DO_HTIMI:
	push	af						; HTIM hook -> need to keep A value
	....                                                   ; Your hook code here
        ld HL,(OLDHOOK)                              ; Old hook address in HL
        pop af						; Restore original A value
	jp	(hl)

Uninstalling the hook is quite complicated as there is a chance someone else hooked after you, but if it is a command line most likely no one will hook after you. That code doesn't take that into consideration as it is not meant to be uninstalled. If you want to uninstall you probably need to check if the hook still has your routine call, if it doesn't, unhooking is not safe, if it still has, you can write the old hook back to H_TIMI...

Those routines already takes into consideration being on any slot and uses interslot call...

Hope that helps

By ducasp

Hero (611)

ducasp's picture

26-07-2022, 23:54

ToriHino wrote:

You should not just change org (since it has to start at 0100h), but copy the part from readKeys to for example C000h. Also make sure when changing the H_TIMI hook to than no longer use the readKeys label but the actual address you copied it to, otherwise it still tries to call your code in page 0. Same goes by the way for all labels used in the copied code (like ShiftKeyPressed). Depending on your assembler there might be a directive to deal with relocated code, which will fix the labels problem for you. An easy solution is to only use JR instead of JP, since this is already relative, regardless the actual location of the code.

Although that will work, unless performance is so critical interslot call can't be used to gain extra cycles, I would recommend not re-allocating the code but instead getting the slot information when installing the hook and using interslot call.

By fpracek

Rookie (25)

fpracek's picture

01-08-2022, 07:37

Thanks for your help.
This weekend I tryed this:

; MSX-DOS entry point
BDOS equ #0005

;MSX BIOS CALLS
KEYINT  equ     #0038
KEYS    equ     #FBE5
H_TIMI  equ     #FD9A
HIMEM   equ     #FC4A
EXPTBL  equ	#FCC1

; MSX-DOS function codes
STROUT  equ #0009

; Constant
HIMSIZE equ 100

; START POINT!
        org #0100

start:
        
        di

        ld hl,H_TIMI
        ld de,oldHook
        ld bc,5
        ldir

        ld	a,#F7					; RST #30
	ld	(H_TIMI),a				; In H_TIMI hook
	call	GetSlot					; Our Slot in A
	ld	(H_TIMI+1),a				; Next H_TIMI hook byte
	ld	hl,readKeys				; Our H_TIMI routine address
	ld	(H_TIMI+2),hl	

        ei
        ret

readKeys:
        ld a,(KEYS+6)
        bit 0,a
        jp z, shiftKeyPressed
        jr oldHook

shiftKeyPressed:
        push de
        ld de, message
        ld c, STROUT
        call BDOS
        pop de
        jr oldHook
message:
        db "Key pressed!$"

GetSlot:
	in	a,(#A8)
	rrca
	rrca
	and	3
	ld	c,a							;C = Slot
	ld	b,0
	ld	hl,EXPTBL
	add	hl,bc
	ld	a,(hl)
	and	#80
	or	c
	ld	c,a
	inc	hl
	inc	hl
	inc	hl
	inc	hl
	ld	a,(hl)
	and	#0C
	or	c
	bit	7,a
	ret	nz
	and	%11
	ret

oldHook:
        db #C9,#C9,#C9,#C9,#C9
; use the label "start" as the entry point
finish:
        end start

Now, the original problem is solved, but when I use "ldir" the "oldHook" remain with all "C9" values...

By NYYRIKKI

Enlighted (5976)

NYYRIKKI's picture

01-08-2022, 10:25

fpracek wrote:

Now, the original problem is solved, but when I use "ldir" the "oldHook" remain with all "C9" values...

This does not sound bad... The hook is used only IF some program or device driver needs this hook. On average day on average setup it is typical that this hook is empty.

By ducasp

Hero (611)

ducasp's picture

01-08-2022, 15:01

fpracek wrote:

Thanks for your help.
This weekend I tryed this:

; MSX-DOS entry point
BDOS equ #0005

;MSX BIOS CALLS
KEYINT  equ     #0038
KEYS    equ     #FBE5
H_TIMI  equ     #FD9A
HIMEM   equ     #FC4A
EXPTBL  equ	#FCC1

; MSX-DOS function codes
STROUT  equ #0009

; Constant
HIMSIZE equ 100

; START POINT!
        org #0100

start:
        
        di

        ld hl,H_TIMI
        ld de,oldHook
        ld bc,5
        ldir

        ld	a,#F7					; RST #30
	ld	(H_TIMI),a				; In H_TIMI hook
	call	GetSlot					; Our Slot in A
	ld	(H_TIMI+1),a				; Next H_TIMI hook byte
	ld	hl,readKeys				; Our H_TIMI routine address
	ld	(H_TIMI+2),hl	

        ei
        ret

readKeys:
        ld a,(KEYS+6)
        bit 0,a
        jp z, shiftKeyPressed
        jr oldHook

shiftKeyPressed:
        push de
        ld de, message
        ld c, STROUT
        call BDOS
        pop de
        jr oldHook
message:
        db "Key pressed!$"

GetSlot:
	in	a,(#A8)
	rrca
	rrca
	and	3
	ld	c,a							;C = Slot
	ld	b,0
	ld	hl,EXPTBL
	add	hl,bc
	ld	a,(hl)
	and	#80
	or	c
	ld	c,a
	inc	hl
	inc	hl
	inc	hl
	inc	hl
	ld	a,(hl)
	and	#0C
	or	c
	bit	7,a
	ret	nz
	and	%11
	ret

oldHook:
        db #C9,#C9,#C9,#C9,#C9
; use the label "start" as the entry point
finish:
        end start

Now, the original problem is solved, but when I use "ldir" the "oldHook" remain with all "C9" values...

That only means your code is the first one to hook, which might happen, as most BIOS/Disk Interfaces will hook to the interrupt signal interrupt (H_KEYI), not the VDP interrupt signal.

Now it is time to you to get that code in better shape. For instance, you don't want to be printing to screen on interrupt, or doing anything that takes long time to complete. This might cause interrupts to be delayed. Also, be careful when using BIOS/DOS or other routines as those might enable interruptions and cause re-entrant interruptions / infinite looping.

Best practice would be to generally have the interrupt code setting a memory flag and have your code, that runs outside interrupt time, reading that flag and acting upon it. You could have, as an example, a byte telling how many key-presses were detected by your hook, and have a copy of it for your code. Whenever the values are different between the copy and the interrupt variable, you know there are key presses to act on (and print the text outside interrupt time). Try to spend the least amount time possible on your interrupt routine to not disrupt other processes that depend on it (i.e.: Keyboard reading, etc). So instead of quitting, after installing the interrupt you might want to jump to your "main program loop". If you are trying to do something that stays resident, this code eventually will fail as you are quitting and eventually that memory will be used for something else, causing the hook to most likely crash. In that case you might want to look at mapper allocation routines and allocate a system mapper segment and move the stay resident routine there, or, move it to page 3 (but then you will need to relocate a lot of stuff on page 3 and update system variables so the system understands that piece of memory is in use and won't be overwritten, that will reduce memory for basic and other programs).

Page 1/2
| 2