Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
upi_conventions [2016/05/27 10:02] ex_writer [SYSTEM and SYSSUK] |
— (current) | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== UPI Conventions ====== | ||
- | Bally Arcade system subroutines are called by executing a RST 38H instruction, followed by one or more parameters. The first parameter is a byte defining which subroutine to execute, whether or not additional parameters for that subroutine follow this parameter, and an indicator bit used for calling user-defined subroutines. | ||
- | |||
- | Example: | ||
- | <code z80> | ||
- | RST 38H ; call subroutine | ||
- | DB 81 ; type, subroutine #, option | ||
- | DB 30 ; passed parameter | ||
- | </code> | ||
- | |||
- | The first byte executes the subroutine call. The second byte is the first parameter. It breaks into the following segments (bits read right-to-left): | ||
- | |||
- | ^ Bit(s) ^ Function ^ Options ^ | ||
- | | 0 | Option | 0 = no parameters follow; 1 = parameters follow in subsequent bytes | | ||
- | | 1–6 | Subroutine number (always even) to transfer to | | | ||
- | | 7 | Subroutine type | 0 = standard subroutine; 1 = user-defined subroutine | | ||
- | |||
- | The option bit (0) specifies how arguments are passed to the system routine. If option = 0, the arguments are presumed to exist in CPU registers; if option = 1, the arguments are taken to follow in subsequent bytes. These arguments are loaded into the CPU registers automatically before the called routine is entered. (The argument(s) required by each system routine are given in the system routine description sections.) | ||
- | |||
- | In the example above, the first parameter byte 81 expands to 01010001B. Bit 0 is 1, indicating that parameters will follow this byte. Bits 1–6, 101000B, indicate subroutine $50 (80D). Bit 7 is set to 0, indicating that this is a standard subroutine call. | ||
- | |||
- | According to the [[rom subroutines|master list]] of onboard subroutines, subroutine 80 is [[human interface#paws|PAWS]], which waits for a user-defined number of interrupts, then returns. It requires one parameter, the number of interrupts, to be passed in B. So the third byte in our example is passing 30 in the B register, requesting a 30-interrupt pause. | ||
- | |||
- | For standard subroutines, programmers do not need to list the verbose RST call as illustrated in the example above. Instead, [[HVGLIB]] provides a list of symbolic identifiers for each system subroutine. Those identifiers are then invoked using the SYSTEM and SYSSUK calls. | ||
- | ===== SYSTEM and SYSSUK ===== | ||
- | |||
- | The Bally Arcade uses two labels, SYSTEM and SYSSUK, to call system routines. Internally, both labels are represented by $FF, the 'system sentinel' byte that readies the Arcade for a system routine number in the following byte. The difference lies in how arguments are passed to the system routine. | ||
- | |||
- | The SYSTEM macro generates the system routine call with option = 0. Option 0 indicates that any system routine arguments will be loaded in their appropriate registers immediately //prior// to the SYSTEM call. | ||
- | |||
- | So, to return to the example above, we could execute the same interrupt wait routine using the following syntax: | ||
- | |||
- | <code z80> | ||
- | LD B,30 | ||
- | SYSTEM PAWS | ||
- | </code> | ||
- | |||
- | The SYSSUK macro generates the system routine call with option = 1. Option 1 indicates that any system routine arguments will be loaded in their appropriate registers directly //after// the SYSSUK call. In other words, the system 'sucks' them into the routine. | ||
- | |||
- | Our same example would now look like this: | ||
- | |||
- | <code z80> | ||
- | SYSSUK PAWS | ||
- | DB 30 | ||
- | </code> | ||
- | |||
- | Both methods have advantages and disadvantages. As Andy Guevara wrote in the '[[http://www.ballyalley.com/ml/ml_docs/Bit%20Fiddler/Bit%20Fiddler's%20Corner%20%281983%29%28Andy%20Guevara%29.pdf|Astrocade Machine Language Programming Tutorial]]': | ||
- | |||
- | >The advantage of the SYSSUK structure is more compact code. The disadvantage is the inflexibility. It is better used for absolute cases than for iterative loops. Like for borders that will always be in the same place, rather than objects that will move across the screen. | ||
- | |||
- | The choice of SYSTEM/SYSSUK depends on your specific programming task. | ||
- | |||
- | ===== The Interpreter ===== | ||
- | Frequently it is desirable to string several system routine calls together. If four or more calls follow in sequence, it is more efficient to use the interpreter, because it voids the overhead of the RST 56 instruction. | ||
- | |||
- | Special call indexes INTPC and EXIT are used to enter and exit interpretive mode, respectively. | ||
- | |||
- | Example: | ||
- | <code z80> | ||
- | SYSTEM INTPC ;BEGIN INTERPRETING | ||
- | DO FILL ;DO FILL ROUTINE | ||
- | DW NORMEM ;START AT TOP OF SCREEN | ||
- | DW 92*BYTEPL ;CONTINUE FOR 92 LINES | ||
- | DB 0 ;FILL WITH ZEROES | ||
- | DO CHRDIS ;DO CHARACTER DISPLAY ROUTINE | ||
- | DB 0 ;CHARACTER Y-COORDINATE | ||
- | DB 10 ;CHARACTER X-COORDINATE | ||
- | DB 8 ;OPTIONS-PLOP, 10-ON, 00-OFF | ||
- | DB 'A' ;CHARACTER TO DISPLAY | ||
- | EXIT ;EXIT INTERPRETER | ||
- | </code> | ||
- | ===== User-Defined Subroutines ===== | ||
- | |||
- | If bit 7 of a subroutine number is set, this call is to a user-defined subroutine. The user must set up the subroutine as follows: | ||
- | |||
- | ^ Location ^ Function ^ | ||
- | | 4FFB/4FFC | (Base address of register load specifications) - 40H | | ||
- | | 4FFD/4FFE | (Base address of subroutine jump table) - 80H | | ||
- | |||
- | [need to integrate with section below] | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | ===== System Routine Format ===== | ||
- | A system routine is coded like a conventional machine language subroutine, except that output parameters are not passed through registers but through the context block. | ||
- | |||
- | The context block is created by the RST 56 call. The user's register set (AF, BC, DE, HL, IX, IY) is pushed onto the stack. Register IY is set to point at this stack frame. Thus a copy of the input arguments exists in RAM, which the system routine may refer to as needed. These arguments are also present in the registers when the system routine is entered, so it is only necessary to refer to the context block when one has clobbered an input argument. | ||
- | |||
- | An output argument is returned to the caller by setting it in the context block. If a register was changed, but the associated cell in the context block was not, then the register will have its old value on return. Thus a system routine is free to use any of the registers it needs without worrying about saving and restoring. The user can also assume that no registers will change except those defined as returning an output argument. | ||
- | |||
- | ==== The Context Block ==== | ||
- | |||
- | The following illustration describes the context block and equates provided in [[HVGLIB]] for each field. | ||
- | |||
- | {{cb_format.png}} | ||
- | |||
- | The UPI uses four tables in the control transfer process. The first two tables give the routine's starting address indexed via call number. The systems table is named SYSDPT. The user may extend this table by storing the address of their extended table into USERTB, USERTB+1. This address should point 128 bytes before the first entry. | ||
- | |||
- | The remaining two tables describe, if specified, the inline arguments a call expects. This table gives a one-byte bitstring, also indexed via call number. The systems name is MRARGT. The user's address is in UMARGT. UMARGT must point 64 bytes ahead. Arguments must follow the call in a specified order. | ||
- | |||
- | Note that the context contains additional information not shown. This information exists both above and below the context. User programs should never use this information or even assume that it exists. The user should only address this area by using IY. | ||
- | ==== Inline Argument Mask Table Entry ==== | ||
- | |||
- | If optioned (i.e., bit 0 of call index is set), the Macro Routine Argument Table (MRARGT) is indexed giving a mask which specifies how to transfer inline arguments into the context block. The mask is formatted as follows: | ||
- | |||
- | {{mask_table.png}} | ||
- | |||
- | Arguments must follow the call index in the following order (if an argument isn't specified, it is omitted.): | ||
- | |||
- | <code>(INDEX), IXL, IXH, E, D, C, B, A, L, H</code> | ||
- | |||
- | Registers that are not defined as containing output parameters will not change. | ||
- | |||
- | All UPI routines are [[glossary#r|reentrant]]. | ||
- | |||
- | ==== Custom System Routines ==== | ||
- | |||
- | The user is responsible for storing the addresses of these tables into dedicated system RAM cells. | ||
- | |||
- | The UPI has been extended to support user-provided system routines. If the interpreter encounters a negative call index, and 'suck inline' is optioned, the user's macro routine address table (USERMT) and argument table (UMARGT) are used. The User Macro Routine Argument Table (UMARGT) is indexed for a parameter mask. The address of this table is assumed to be in (UMARGT),(UMARGT+1). This pointer should point 64 bytes before the first real entry. | ||
- | |||
- | [**Note:** Section needs clarification. Does the source listing have the wrong labels listed??] | ||
- | |||
- | Example: | ||
- | <code z80> | ||
- | LD HL,USERMT-64 ; WHERE USERMT POINTS AT | ||
- | LD (UMARGT),HL | ||
- | </code> | ||
- | |||
- | ---- | ||
- | |||
- | |||
- | [NM:2-7, source listing p. 20] |