Author Topic: Difficulties to replace TEXT_INPUT system call by my own routine  (Read 497 times)

0 Members and 1 Guest are viewing this topic.

Offline krusty_benediction

  • CPC664
  • ***
  • Posts: 95
  • Country: fr
  • Liked: 79
Hello,

I'm trying to add functionalities to the CPC system with something similar to QuickCMD, but deeply integrated within the system (i.e. not inside an application) and more autocompletions.
Thus it is a ROM which replaces the system call TEXT_INPUT to improve the editing experience and add an additional interpretor which treats the input before BASIC interpretor.

Sadly, it does not really work for the moment :(

I have a standalone executable which does not replace TEXT_INPUT and where I have manually wrote a loop which calls my routine to get the user input; this one works as BASIC interpreter is not involved.
I have a ROM version which replaces TEXT_INPUT and which fails when going back to the BASIC: Syntax Error is systematically displayed, whatever is the input string.

I'm searching my mistakes since several days and I have no idea of its origin. Maybe someone can help me ?

 - If I have a bug in my code, I doubt you can help me; it may be long and tedious to read the code.
 - If I do not properly use ROM creation and system call replacement, I think you can help me.
 
 Some explanations follow.
 
 When the ROM initializes itself, it reserves 3 bytes of memory and store it the address of my TEXT_INPUT function (i.e. word address in ROM space + ROM number) and modify the TEXT_INPUT entry in the firmware jump table to do a FAR_CALL to this 3 bytes of memory.
So when TEXT_INPUT is called, it is my version which is used. It is roughly the same that the original one, except that (i) I have modified some entries of in the mapping table of key to function in order to add an history functionality, (ii) I have added an entry to TAB to manage autocompletion, and (iii) I have modified the function called when pressing RETURN to add text to history, call my own interpretor (if I interpret something, I modify the string to be null in order to not generate errors in BASIC, so: BC=0 and (HL)=0). My TEXT_INPUT function preserves the registers as with the original one. The current version uses extra memory to store its buffers (will change that later) in 0x4000-0x7fff area of Bank 7, Page 7 (X-MEM or equivalent required).
Note that even if I deactivate my patches added to the RETURN callback function, the issue remains. So the bug does not come from the history or interpretor managements I have added.
 
 There are breakpoints (Winape breakpoints) in my source: when TXT_INPUT is called, when the RETURN callback function is called and leaved.
 
 The code is accessible here: https://github.com/rgiot/bndsh.
 The current ROM version is also available: https://github.com/rgiot/bndsh/blob/master/BNDSH.ROM. It can be deactivated by pressing ESC at launch.
 
 
 
 Thanks

Offline krusty_benediction

  • CPC664
  • ***
  • Posts: 95
  • Country: fr
  • Liked: 79
To provide more information, when my version of TEXT_INPUT is finished, the system calls a routine in 0x2f91 which moves a real from one place to another. The result is that the buffer which contains the string is modified because it is the destination of this copy.
Still no idea why this function is called as it is not the case when the same string is typed with the original TEXT_INPUT function :(


Offline arnoldemu

  • Supporter
  • 6128 Plus
  • *
  • Posts: 5.273
  • Country: gb
    • Unofficial Amstrad WWW Resource
  • Liked: 2152
To provide more information, when my version of TEXT_INPUT is finished, the system calls a routine in 0x2f91 which moves a real from one place to another. The result is that the buffer which contains the string is modified because it is the destination of this copy.
Still no idea why this function is called as it is not the case when the same string is typed with the original TEXT_INPUT function :(
Your patch to BD5E is using an rst 3 which is like a rom "call". The firmware functions use a rst 1 which is like a rom "jp".
So it is executing the next firmware function in the block which is one of the real number functions.

Put a breakpoint on bd5e, step over or step in to see it doing this :)

EDIT: The firmware jumpblock has 3 bytes for each entry and the rst 3 is 3 bytes. AMSDOS puts rst 3 as you do but it plays a trick here - it changes the stack.



« Last Edit: 16:01, 22 June 17 by arnoldemu »
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

Offline krusty_benediction

  • CPC664
  • ***
  • Posts: 95
  • Country: fr
  • Liked: 79
I have not well understand. My code is in a ROM, so I though it was normal to do a ROM call.
I cannot test now; do you suggest to do a RST 1 somewhere in main memory + at this place doing a RST 3 call ?

Offline arnoldemu

  • Supporter
  • 6128 Plus
  • *
  • Posts: 5.273
  • Country: gb
    • Unofficial Amstrad WWW Resource
  • Liked: 2152
I have not well understand. My code is in a ROM, so I though it was normal to do a ROM call.
I cannot test now; do you suggest to do a RST 1 somewhere in main memory + at this place doing a RST 3 call ?
This code does it:

Code: [Select]
;; Patch a firmware function so it calls into our ROM
;;
;; We need to use RST3 because it allows a CALL to a function in a ROM.
;; RST3 has this form:
;;
;; rst 3
;; defw address of rst3 data
;;
;; rst3 data:
;; +0: 2 byte address to call
;; +2: 1 byte rom select
;;
;; The rst3 data must be in the main 32KB of RAM.
;;
;; However we can't write the RST3 direct into the firmware jumpblock because
;; it will act as a CALL and when returned from it will return inside the firmware jumpblock
;; and execute the next function.
;;
;; Normally jumpblock uses RST1 which is a JP like instruction into a lower ROM
;; function.
;;
;; There is no RST which is a jump into ROM.
;;
;; So patch the firmware jumpblock with JP and call into RAM we reserve for our
;; ROM. The RAM has code to execute an RST and return.


original_firmware_fn equ 0        ;; 3 bytes read from jumpblock (this is the "old" firmware function)
jump_code equ original_firmware_fn+3 ;; code called by JP from firmware.
                                    ;; RST 3                  1 byte
                                    ;; defw <address>        2 bytes
                                    ;; RET                    1 byte
rst3_data equ jump_code+4            ;; defw <address>        2 bytes
                                    ;; defb 1                1 byte rom select
rom_data_total equ rst3_data+3

;;--------------------------------------------------------------------------------------
;; firmware functions
kl_curr_selection equ &b912
txt_output equ &bb5a
;;--------------------------------------------------------------------------------------
rst3_instruction equ &df
ret_instruction equ &c9
jp_instruction equ &c3
;;--------------------------------------------------------------------------------------

function_to_patch equ &bd5e


;; location for upper roms
org &c000

start:
;; bd61
;; rom header
defb 1            ;; type
defb 1            ;; mark
defb 0            ;; version
defb 0            ;; modification
defw name_table
jp boot

;;-----------------------------------------------------------------------------

;; name table
name_table:
defb "NEW RO","M"+&80       
defb 0

;;-----------------------------------------------------------------------------

boot:
push ix

;; allocate upper RAM for our ROM
or a
ld bc,rom_data_total+1
sbc hl,bc
push hl
push de
inc hl

push hl
pop ix    ;; IX = start of ram

;; copy old firmware jumpblock data into ram
ex de,hl
ld hl,function_to_patch
ld bc,3
ldir

ld (ix+jump_code),rst3_instruction

push ix
pop hl
ld bc,rst3_data
add hl,bc
;; hl = address of rst3 data in ram
ld (ix+jump_code+1),l
ld (ix+jump_code+2),h

ld (ix+jump_code+3),ret_instruction

;;-----------------------------------------
;; setup rst 3 data
ld de,new_function
ld (ix+rst3_data+0),e
ld (ix+rst3_data+1),d
call kl_curr_selection        ;; get our rom id
ld (ix+rst3_data+2),a

;;-----------------------------------------
;; patch firmware jumpblock
ld a,jp_instruction
ld (function_to_patch+0),a

push ix
pop hl
ld bc,jump_code
add hl,bc
;; HL = address of jump_code in RAM
ld (function_to_patch+1),hl

pop de
pop hl
pop ix
;; initialisation successful
scf
ret

;;-------------------------------------------------
;; this is our new function for bd5e
;; HL = address of buffer for text
;; IY = start of RAM allocated for ROM
new_function:
;; do something first
push hl
ld a,'A'
call txt_output

pop hl

jp (iy)    ;; call original firmware function copied into ram

end start

AMSDOS uses another method which I will explain tomorrow and which is better if you are patching many functions.

My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

Offline krusty_benediction

  • CPC664
  • ***
  • Posts: 95
  • Country: fr
  • Liked: 79
Thanks again for pointing my error

The following longer code fixes the mistake (I'll test deeply tonight)
Code: [Select]
;;
; Input :
; HL: address where to jump
input_txt_replace_firmware
.rst_18_instruction equ &df
.jp equ 0xc3
.call equ 0xcd
.ret equ 0xc9
.ld_hl equ 0x21
.ld_c equ 0x0e
.ex_de_hl equ 0xeb


  if 1
    ld a, .jp
    ld (FIRMWARE.TEXT_INPUT+0), a
    ld (FIRMWARE.TEXT_INPUT+1), hl
  endif

  if 1:
    push hl : call FIRMWARE.KL_CURR_SELECTION : pop hl
    ld de, new_line_editor

    ; Write far call
    ld (hl), .ex_de_hl : inc hl
    ld (hl), .ld_hl: inc hl
    ld (hl), e : inc hl
    ld (hl), d : inc hl
    ld (hl), .ld_c : inc hl
    ld (hl), a : inc hl
    ld (hl), .call : inc hl
    ld de, FIRMWARE.KL_FAR_PCHL
    ld (hl), e : inc hl
    ld (hl), d : inc hl
    ld (hl), .ret
  endif
  ret

Ineed it takes more memory