Most of the PRGM-functions are called via syscalls. Some of the PRGM-functions are more or less worthless.
Such a function can be redirected by redirecting the
corresponding syscall, like
0x0CB0: int PRGM_Send( char**program, short*opcode,
TBCDvalue result[2] );
, which is called if Send() or Send38k() is called from out of a PRGM-program.
The replacement code has to be positioned at a fixed
position, f. i. in sector 0x80220000, which is a unused sector throughout
every fx-9860-OS. While developing some RAM could be used for convenience. F.
i. onchip-RAM 0xA5600600 to 0xA5603A97 or 0x88040000 on 512k RAM-machines.
When using the onchip-RAM, at any rate the code must
not exceed the allowed limits!
1. most important: make a backup of the OS of the calculator, where the PRGM extension should be installed.
2. find the address of syscall 0xCB0:
- read the pointer at fileoffset 0x0001007C: *(int*)0x8001007C
- subtract 0x80000000: *(int*)0x8001007C - 0x80000000
- now we have the fileoffset to the syscall-table.
- calculate the address of the syscall: ( *(int*)0x8001007C - 0x80000000 ) +
0xCB0*4
- subtract 0x80000000 again: ( ( *(int*)0x8001007C - 0x80000000 ) + 0xCB0*4 )
- 0x80000000
- now we have the fileoffset of syscall's 0xCB0 code, which has to be replaced.
- hint: the first four bytes must be 0x2F 0xE6 0x6E 0x53.
3. the syscall's replacement code would look like
mov.l #h'A5600600, r2
jmp @r2
nop
or
mov.l #h'88040000, r2
jmp @r2
nop
or
mov.l #h'80220000, r2
jmp @r2
nop
After assembly it is either ( in case of the syscall-address is 4-aligned)
D2 01
42 2B
00 09
00 00
A5 60 06 00 (or 88 04 00 00 or 80 22 00 00)
or ( in case of the syscall-address is not 4-aligned)
D2 01
42 2B
00 09
A5 60 06 00 (or 88 04 00 00 or 80 22 00 00)
F. i. on GII OS 2.00: 0x80187340 is 4-aligned, hence use the first block.
4. Now the replacement code must be assembled and bound. That requires the use of SHC/SHCPP, ASMSH and OPTLNK separately, t. i. not in the course of regular SDK-build. The SDK locates the code at 0x00300200 and inserts some initialization code, which would must not be inserted.
OK. I usually prefer small steps, if it comes to solve
difficult problems, but here is the whole bunch for a start.
Sorry, if it seems to be overwhelming.
There is no doubt, that depending on different work environments, this scheme
may not work at once and will lead to some complaints. But usually such
inconveniences can be mended by minor adjustments. Do not despair. Simply ask
instead.
You need a replacement function. You could write it in
assembler, but more convenient is C/C++, of course. I prefer SHCPP because it
issues a lot more warnings than SHC and so helps to prevent some avoidable
errors. Lets call the source module CLIB.CPP.
The interface must be
int CLIB_entry( char**program, short*opcode, TBCDvalue
result[2] );.
In the old documentation, the parameters program
and opcode have been arranged in the wrong order! Sorry for that.
Here is the minimum frame for this function. It has to process the opcodes
until an EndOfLine has been encountered, before returnning control to PRGM!
Two syscalls are needed for that. What you do around this absolutely necessary
frame is up to you. Return 1 if you want to report success. Return 0 if you
want to report failure. In case of failure, you have to provide for some error
information in TBCDvalue result[2]. If you do not provide for error
information, the calc will crash!
Now the makefile PRGM0CB0.hmk:
The SHCPP-option -I= must be set to the comma-separated
list of INCLUDE-directories, if needed.
The path must contain the directory, where the CASIO SDK-binaries reside:
usually ...\CASIO\fx-9860G SDK\OS\SH\BIN
The compiler needs the following environment variables:
SET SHC_LIB=usually ...\CASIO\fx-9860G SDK\OS\SH\BIN
SET SHC_TMP=some directory, where the user has write-rights (with CASIO SDK it
is the directory called "..\debug")
Then a main assembler frame is required to ensure, that the entry of your replacement code will be at the top of the resulting binary. It could look like this (f. i. PRGM0CB0.ASM). CLIB_entry is the function in your CLIB.obj, which must be called, when the redirected syscall is invoked:
The following makefile will assemble the main frame:
Finally PRGM0CB0.obj and CLIB.OBJ has to be linked together to give the resulting binary.
setup.obj can be found in the CASIO SDK directory ...\CASIO\fx-9860G
SDK\OS\FX\lib.
Depending on the complexity of CLIB.CPP, additional input- and/or
library-declarations possibly must be included.
Before transferring the binary to the calculator the file PRGM0CB0.MAP should be inspected to ensure, that the entry is at 0x88070000. Maybe CLIB.LST and PRGM0CB0.LST should be inspected, too.
(31.05.2012 15:00:08)