;* ======================================================================== *; ;* The routines and data in this file (emu_link.mac) are dedicated to the *; ;* public domain via the Creative Commons CC0 v1.0 license by its author, *; ;* Joseph Zbiciak. *; ;* *; ;* https://creativecommons.org/publicdomain/zero/1.0/ *; ;* ======================================================================== *; ;; ======================================================================== ;; ;; Emu-Link Support Macros ;; ;; ;; ;; Emu-Link is a simple mechanism that allows an Intellivision program ;; ;; to interact with an Intellivision emulator to gain access to emulator ;; ;; specific functionality. ;; ;; ;; ;; Currently, only jzIntv supports Emu-Link, although in principle any ;; ;; emulator could. Emu-Link provides a dedicated API for determining ;; ;; what emulator (if any) it's currently running under, as well as ID ;; ;; strings for them, should they ever decide to add this feature. ;; ;; ;; ;; All APIs other than EL_EMU_DETECT adhere to the following basic ;; ;; protocol: ;; ;; ;; ;; -- Program loads $4A5A into R0 as a magic signature ;; ;; -- Program loads EMU_LINK call # into R1 ;; ;; -- Program puts whatever arguments in R2..R5 [1] ;; ;; -- Program sets the carry bit (C = 1) [2] ;; ;; -- Program issues SIN ;; ;; -- Emulator checks R0 for signature and R1 for call # ;; ;; -- If no signature, treat SIN as NOP ;; ;; -- If signature OK but call # invalid, set C=1, R0=FFFF ;; ;; -- If signature OK and call # valid, set C=0 and execute call ;; ;; -- Callee executes, returning pass/fail in C, result in R0..R5. ;; ;; ;; ;; [1] Emu-Link APIs can access the Intellivision's RAM, so large ;; ;; structures can be passed through memory. Furthermore, the APIs ;; ;; need not clobber all of the CPU registers. As with native asm ;; ;; calls, the set of modified registers varies with each API. ;; ;; ;; ;; [2] Setting carry is optional if the program has already determined ;; ;; that Emu-Link is present. The SIN instruction does not modify ;; ;; the carry, and so setting carry before SIN makes sure all Emu- ;; ;; Link calls appear to fail. ;; ;; ======================================================================== ;; IF (DEFINED _EMU_LINK_MAC) = 0 _EMU_LINK_MAC QEQU 1 ;; ======================================================================== ;; ;; EL_EMULATOR A set of constants for the emulator IDs. ;; ;; ======================================================================== ;; EL_EMULATOR PROC @@jzintv QEQU ('J' SHL 8) OR 'Z' ; "JZ" => jzIntv @@kinty QEQU ('K' SHL 8) OR 'I' ; "KI" => Kinty @@bliss QEQU ('B' SHL 8) OR 'L' ; "BL" => Bliss @@nost QEQU ('N' SHL 8) OR 'O' ; "NO" => Nostalgia @@intvwin QEQU ('I' SHL 8) OR 'W' ; "IW" => IntvWin @@intvdos QEQU ('I' SHL 8) OR 'D' ; "ID" => IntvDos @@intvpc QEQU ('I' SHL 8) OR 'P' ; "IP" => IntvPC ENDP ;; ======================================================================== ;; ;; EL_CPU_REGS Utility symbols. ;; ;; ======================================================================== ;; EL_CPU_REGS PROC @@R0 QEQU 0 @@R1 QEQU 1 @@R2 QEQU 2 @@R3 QEQU 3 @@R4 QEQU 4 @@R5 QEQU 5 @@R6 QEQU 6 @@R7 QEQU 7 @@SP QEQU 6 @@PC QEQU 7 ENDP MACRO _el_2c(a,c1,c2) ((ASC("%a%",0)='%c1%') AND ((ASC("%a%",1))='%c2%')) ENDM MACRO _el_isreg(a) ((STRLEN("%a%")=2) AND (((ASC("%a%",0)='R') AND (ASC("%a%",1) >= '0') AND (ASC("%a%",1) <= '7')) OR _el_2c(%a%,S,P) OR _el_2c(%a%,P,C))) ENDM ;; ======================================================================== ;; ;; EL_EMU_DETECT Detect if an emulator is present, and if so, which. ;; ;; ;; ;; OUTPUTS ;; ;; C C=0 indicates an emulator was detected, C=1 means none. ;; ;; ;; ;; R0 Emulator ID (one of the constants in EL_EMULATOR above), ;; ;; or the constant $656D if none detected. ;; ;; ;; ;; R1 Emulator version (major in upper 8, minor in lower 8) or ;; ;; the constant $753F if none detected. ;; ;; ;; ;; R2..R5 Unmodified ;; ;; ======================================================================== ;; MACRO EL_EMU_DETECT MVII #$656D, R0 ; \_ "em" MVII #$753F, R1 ; / "u?" SETC SIN ENDM ;; ======================================================================== ;; ;; EL_CALL Make Emu-Link API call, w/out SETC (smaller, faster) ;; ;; EL_CALL_SC Make Emu-Link API call, with SETC (larger, safer) ;; ;; ;; ;; INPUTS ;; ;; API ID API number being invoked. At the time of writing: ;; ;; 0 Ping: An alternate way to test for Emu-Link. ;; ;; 1..7 Reserved ;; ;; 8 Get raw analog joystick input (el_joy.mac) ;; ;; 9 Get raw events (el_event.mac) ;; ;; 10..17 File I/O (el_fileio.mac) ;; ;; The API number can be a constant or passed in a register. ;; ;; ;; ;; R2..R5 Arguments to the API ;; ;; ;; ;; OUTPUTS ;; ;; C 0 == success, 1 == failure ;; ;; R0..R5 Output from API. R0 and R1 are clobbered even if Emu- ;; ;; Link is not present. ;; ;; ;; ;; ======================================================================== ;; MACRO EL_CALL api IF _el_isreg(%api%) IF EL_CPU_REGS.%api% <> 1 MOVR %api%, R1 ENDI ELSE MVII #%api%, R1 ENDI MVII #$4A5A, R0 SIN ENDM MACRO EL_CALL_SC api SETC EL_CALL %api% ENDM ;; ======================================================================== ;; ;; EL_PING Call the Emu-Link 'ping' API ;; ;; ;; ;; OUTPUT ;; ;; C = 0, R0 == 0: Success ;; ;; C = 1, R0 != 0: Failure ;; ;; R1 zeroed ;; ;; ======================================================================== ;; MACRO EL_PING EL_CALL_SC 0 ENDM ENDI