Difference between revisions of "Free call to BIOS routine"

From MSX Game Library

 
(2 intermediate revisions by the same user not shown)
Line 3: Line 3:
 
The idea is to "cast" an address with the signature of a C function so that the calling code initializes the registers properly before calling the BIOS function.
 
The idea is to "cast" an address with the signature of a C function so that the calling code initializes the registers properly before calling the BIOS function.
  
For example, the function <tt>GTSTCK</tt> (<tt>00D5h</tt>) which returns the status of the joystick, takes its input parameter in A and returns its final value in A. Among the possible function signatures, <tt>(u8(*)(u8))</tt> uses these same registers (<tt>u8</tt> is <tt>unsigned char</tt>).
+
For example, the function <tt>GTSTCK</tt> (<tt>00D5h</tt>) which returns the status of the joystick, takes its input parameter in A and returns its final value in A. Among the possible function signatures, <tt>(u8(*)(u8))</tt> uses these same registers.
  
 
Thus, with this function definition...
 
Thus, with this function definition...
 
  inline u8 Bios_GetJoystickDirection(u8 port) { return ((u8(*)(u8))R_GTSTCK)(port); }
 
  inline u8 Bios_GetJoystickDirection(u8 port) { return ((u8(*)(u8))R_GTSTCK)(port); }
...the calling code will put the port number into A, call the <tt>GTSTCK</tt> function, then read the result into A.
+
...the calling code will put the port number into register A, call the <tt>GTSTCK</tt> function, then read the result into register A.
  
 
Since the function is inline, we gain C typing verification, while having zero C overhead.
 
Since the function is inline, we gain C typing verification, while having zero C overhead.
  
Obviously, this only works with BIOS routines that use registers for which there is a C function signature. There are few of them, but by playing with the <tt>sdcccall1</tt> and <tt>z88dk_fastcall</tt> calling conventions, we still have some possibilities.
+
Obviously, this only works with BIOS routines that use registers for which there is a C function signature. There are few of them, but by playing with the <tt>sdcccall1</tt> and <tt>z88dk_fastcall</tt> calling conventions, we still have some possibilities. In the case of a <tt>z88dk_fastcall</tt> signature you have to use a <tt>typedef</tt> to define the signature before you can use it.
 
 
In the case of a <tt>z88dk_fastcall</tt> signature you have to use a <tt>typedef</tt> to define the signature before you can use it.
 
  
 
Here is a summary of all possible the combinations:
 
Here is a summary of all possible the combinations:

Latest revision as of 23:15, 8 July 2022

Here is a technique to remove 100% of the C language overhead on calling some of the BIOS routines.

The idea is to "cast" an address with the signature of a C function so that the calling code initializes the registers properly before calling the BIOS function.

For example, the function GTSTCK (00D5h) which returns the status of the joystick, takes its input parameter in A and returns its final value in A. Among the possible function signatures, (u8(*)(u8)) uses these same registers.

Thus, with this function definition...

inline u8 Bios_GetJoystickDirection(u8 port) { return ((u8(*)(u8))R_GTSTCK)(port); }

...the calling code will put the port number into register A, call the GTSTCK function, then read the result into register A.

Since the function is inline, we gain C typing verification, while having zero C overhead.

Obviously, this only works with BIOS routines that use registers for which there is a C function signature. There are few of them, but by playing with the sdcccall1 and z88dk_fastcall calling conventions, we still have some possibilities. In the case of a z88dk_fastcall signature you have to use a typedef to define the signature before you can use it.

Here is a summary of all possible the combinations:

You can found many examples in engine\src\bios.h.