Star Tip 8 - 128K routines - "Program Pitstop"
by David Jones
from Your Sinclair 24 (Dec.1987)


David Jones is no stranger to these pages, having contributed a
brilliant little tip to last month's Shop. Being a generous kind of
gut, he's listed out some useful routines for 128 programmers, which
you can use to make really whizzy games. Not much explanation is
needed, because the routines are heavily commented, but here's a quick
resume of what they do.

PSWAP    - 128 page swap
PAGEA    - calls sub-routine on any page
IMODESET - sets up Interrupt Mode 2
IMODE    - Interrupt handler
MUSICON, MUSICOFF, PLAYIT - samples of how to call a sub-routine

[There was no MUSICOFF routine listed in the magazine. JimG]


RAM PAGE ALLOCATION

--- ROM ---!-- PAGE 2 --!- FIXED RAM -!--
           !- SCREEN$1 -!-- PAGE 5 --! USL
PAGE 0 - NORMALLY RESIDENT AT C000H
INTERRUPT VECTORS AND MAIN CODE
PAGE 1 -                AT C000H
PAGE 2 - FIXED RAM PAGE AT 4000H
PAGE 3 -                AT C000H
PAGE 4 -                AT C000H
PAGE 5 - FIXED RAM PAGE AT 8000H
PAGE 6 -                AT C000H
PAGE 7 - SCREEN$ 2      AT C000H


MUSICFLG: DB 0
DEFSCR:   DB 0
FIXPAGE:  DB 0
PAGENO:   DB 0

;Note: These subroutines must be placed below C000H to work properly.
;      Crashes result otherwise.

PAGEPORT: EQU 7FFDH

;This subroutine will change the page at C000H.
;Entry Conditions:
;A register = new page number
;Exit Conditions:
;FIXPAGE contains new page number
;A register = value sent to port
;All other registers preserved

PSWAP:    PUSH BC
          LD (FIXPAGE),A
          LD C,A
          LD A,(DEFSCR)
          ADD A,C         ;add 8 if alternate screen is on show
          OR 16
          LD BC,PAGEPORT  ;ensure Spectrum ROM always present
          OUT (C),A
          POP BC
          RET

;CALL a subroutine on a given page at a given address.
;Entry Conditions:
;A register = page number
;HL register pair = address of subroutine
;Exit Conditions:
;FIXPAGE contains new page number
;A register = value sent to port
;All other registers preserved

PAGEA:    LD (PAGEAV+1),HL
          CALL PSWAP
PAGEAV:   CALL 0          ;call address supplied in HL on entry at PAGEA
          PUSH AF
          XOR A
          CALL PSWAP      ;set page 0 in place (normal 48K page)
          POP AF
          RET

;Music Control Routines

MUSICON:  LD HL,MON       ;address of Music On subroutine
          LD A,MPAGE      ;page number where music is stored
          JR PAGEA

PLAYIT:   LD A,(MUSICFLG)
          OR A
          RET Z
          LD HL,MPLAY     ;address of Play Music subroutine
          LD A,MPAGE      ;page number where music is stored
          JR PAGEA


;Interrupt Mode Setup

;Top useable memory address equals 0FFF3H (65523)
;due to interrupt control code.
;FFF4H  IVECTOR:JP IMODE
;FFF7H  @BB8   :DS 8      ;(8 byte temp store buffer)
;FFFFH          JR IVECTOR

IMODESET: POP HL          ;return address
          LD SP,NEWSTACK
          PUSH HL
          XOR A
          LD (DEFSCR),A
          LD (IY+65),A    ;IMODE off
          LD (IY+87),3    ;OVER 1
          LD (IY+48),8    ;CAPS on
          LD HL,IMODETAB
IMODELP:  LD A,(HL)
          CP 255
          JR Z,IMODELX
          PUSH HL
          CALL PSWAP
          LD A,18H
          LD (0FFFFH),A
          LD A,0C3H
          LD (0FFF4H),A   ;JP IMODE
          LD HL,IMODE
          LD (0FFF5H),HL
          POP HL
          INC HL
          JR IMODELP
IMODELX:  XOR A
          CALL PSWAP
          LD HL,0BE00H
          LD A,H          ;place in I reg below
          LD DE,0BE01H
          LD BC,256
          LD (HL),255
          LDIR            ;build 257*0FFH table
          DI
          LD I,A
          EI
          HALT
          XOR A
          LD (IY+65),A
          IM 2            ;re-vectored interrupts
          RET

IMODETAB: DB 0,1,3,4,6,7,255

;Interrupt Handler
;Note that this doesn't do anything useful here except play the tune,
;which can be placed on a different page. I have included it so that
;you can place your own sub-routines below (ie. Sprites).

IMODE:    PUSH AF
          LD A,(FIXPAGE)
          LD (IMODEV+1),A
          CALL PLAYIT
;Place your sub-routines here
          LD HL,(FRAMES)
          INC HL
          LD (FRAMES),HL
          LD A,H
          OR L
          JR NZ,IMODEX
          INC (IY+64)     ;FRAMES+2
IMODEX:   CALL 02BFH      ;keyboard scan
IMODEV:   LD A,0
          CALL PSWAP
;Now POP all the registers that you pushed earlier.
          POP AF
          EI
          RET

