sexta-feira, 22 de novembro de 2019

Dica: Devolver um número de uma rotina C/M

Se querem correr alguma rotina C/M que apenas vai fazer operações para devolver um número, não precisam de fazer a impressão em rotinas assembly/ C/M.

Note-se que ao voltar de uma rotina C/M podem devolver o número no registo BC.

Como exemplo:

ORG 50000
LD    BC,20

E então a partir de BASIC:

10 PRINT USR 50000

Irá imprimir 20.

Vendo a rotina da ROM de retornar ao BASIC,  é 2D2B: THE 'STACK-BC' SUBROUTINE


Used by the routines at S_RND, DEC_TO_FP, usr and len.
The routine at STACK_A continues here.
This subroutine gives the floating-point form for the absolute binary value currently held in the BC register pair.

The form used in this and hence in the two previous subroutines as well is the one reserved in the Spectrum for small integers n, where -65535<=n<=65535. The first and fifth bytes are zero; the third and fourth bytes are the less significant and more significant bytes of the 16 bit integer n in two's complement form (if n is negative, these two bytes hold 65536+n); and the second byte is a sign byte, +00 for '+' and +FF for '-'.

BC Value to stack
STACK_BC 2D2B LD IY,$5C3A Re-initialise IY to ERR-NR.
2D2F XOR A                         Clear the A register.
2D30 LD E,A                         And the E register, to indicate '+'.
2D31 LD D,C                         Copy the less significant byte to D.
2D32 LD C,B                         And the more significant byte to C.
2D33 LD B,A                         Clear the B register.
2D34 CALL STK_STORE       Now stack the number.
2D37 RST $28                          Use the calculator to make HL point to STKEND-5.
2D38 DEFB $38                 End_calc
2D39 AND A                         Clear the carry flag.
2D3A RET                                 Finished.

A rotina equivalente de entrar em C/M a partir do USR, também coloca em BC a direcção da rotina C/M, neste caso 50000, e é 34B3: THE 'USR' FUNCTION (offset +2D)

The address of this routine is found in the table of addresses. It is called indirectly via fp_calc_2.
This subroutine ('USR number' as distinct from 'USR string') handles the function USR X, where X is a number. The value of X is obtained in BC, a return address is stacked and the machine code is executed from location X.
usr_no 34B3 CALL FIND_INT2 Evaluate the 'last value', rounded to the nearest integer; test 
                                                                 that it is in range and return it in BC.
        34B6 LD HL,$2D2B         Make the return address be that of the subroutine
        34B9 PUSH HL
        34BA PUSH BC          Make an indirect jump to the required location.

        34BB RET

Note: it is interesting that the IY register pair is re-initialised when the return to STACK_BC has been made, but the important HL' that holds the next literal pointer is not restored should it have been disturbed. For a successful return to BASIC, HL' must on exit from the machine code contain the address of the 'end-calc' instruction at +2758.

34B3: THE 'USR' FUNCTION (offset +2D)

Por exemplo, nesta rotina:

        ORG     50000
        LD      IX,16384
        LD      DE,6912
        LD      A,$FF
        BIT     0,C
        JR      Z,LD_ENTRY

        JP      SA_BYTES

A entrar por RAND USR 50000 vai para LD_ENTRY e por RAND USR 50001 salta para SA_BYTES

Note-se, que já que estamos a falar deste tema, que as rotinas código M/C têm de preservar o valor de HL´ antes de voltar ao BASIC (ou restaurá-lo a $2758). Como nota adicional, chamar funções de ROM  a partir de C/M que necessitem de usar o stack FP implica não mexer ou restaurar o registo IY.

1 comentário:

  1. IY tem de ser sempre $5C3A para usar as rotinas da ROM e a rotina IM 1 da ROM.