                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Module: BS
;>
;>      This module contains all the routines that are used in bankswitching.
;>
;>      PROCEDURE Bank_Call( Address : PTR { !!r0 } )
;>      PROCEDURE LookUp_Rom( HiAddress : BYTE { !r0 }
;>      PROCEDURE Bank_Ret
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Procedure: Bank_Call
;>
;>      This procedure manages subroutine calls from one bank of
;>      the controllers external program space to the other. If
;>      one routine wants to call another routine in a different 
;>      memory bank it must do indirectly through this routine.
;>
;>      Inputs:
;>              Address : PTR { !!r2 }
;>
;>      Outputs: { none }
;>
;>      Algorithm:
;>
;>      BEGIN
;>       LookUp_Rom( Address DIV 256 )
;>       Goto @Address
;>      END
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     Internal
                .LSTON
                .Page
                .FIN

Bank_Call:
                Push    Rp
                Ld      Wrk_Sys2+$4,Rp ;save Rp for reference later
                Srp     #Wrk_Sys2
                
                Add     !r4,#2 ;get reg 2 in original Rp
                Ld      !r0,@!r4 ;get hibyte of called adr
                Call    LookUp_Rom
                
                Pop     Rp
                Jp      @!r2
                
                .LSTOFF
                .DO     External
                .LSTON
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Procedure: LookUp_Rom
;>
;>      This procedure is used to determine which of five 4k
;>      banks of program space the user wishes to execute within.
;>
;>      Inputs:
;>              HighAddress : BYTE { !r0 }
;>
;>      Outputs: none
;>
;>      Algorithm:
;>
;>      BEGIN
;>       CASE HighAddress OF
;>        0 : Adr13 := 0, Adr12 := 0
;>        1 : Adr13 := 0, Adr12 := 0
;>        2 : Adr13 := 0, Adr12 := 1
;>        3 : Adr13 := 1, Adr12 := 0
;>        4 : Adr13 := 1, Adr12 := 1
;>       OTHERWISE Abort
;>      END
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     Internal
                .LSTON
                .Page
                .FIN
                
LookUp_Rom:     Tm      !r0,#$80 ;check for adr out of range
                Jr      Nz,LU_Abort
                And     !r0,#$70 ;mask off unnecessary stuff from address
                Cp      !r0,#$40
                Jr      Le,BC_1
                
LU_Abort:       Call    Abort

BC_1:           Ld      !r2,#.HIBYTE. Rom_Table
                Ld      !r3,#.LOWBYTE. Rom_Table
                Swap    !r0 ;turn highaddress into index value
                Rl      !r0 ;multiply index by 2 { 2 byte/element table }
                Add     !r3,!r0 ;index into table
                Adc     !r2,#0
                Ldc     !r1,@!!r2 ;get rom address values
                Incw    !!r2
                Ldc     !r0,@!!r2
                
                Ld      !r2,#.HIBYTE. RomBank0
                Ld      !r3,!r0
                Lde     @!!r2,!r3 ;set EpromBank0,1
                Ld      !r2,#.HIBYTE. RomBank2
                Ld      !r3,!r1
                Lde     @!!r2,!r3 ;set EpromBank2,3
                Ret
                
RomTable:       .DB     0,0 ;Adr13 := 0, Adr12 := 0
                .DB     0,0 ;Adr13 := 0, Adr12 := 0
                .DB     0,1 ;Adr13 := 0, Adr12 := 1
                .DB     1,0 ;Adr13 := 1, Adr12 := 0
                .DB     1,1 ;Adr13 := 1, Adr12 := 1
                
                .LSTOFF
                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Procedure: Bank_Ret
;>
;>      This procedure is used as the return linkage when another
;>      procedure wishes to return to a location that is not
;>      in the same external program bank.
;>
;>      Inputs: { none }
;>
;>      Outputs: { none }
;>
;>      Algorithm:
;>
;>      BEGIN
;>       Address.HiByte := Stack[ StackPtr ]
;>       Address.LoByte := Stack[ StackPtr - 1 ]
;>       LookUp_Rom( Address DIV 256 )
;>       Goto @Address
;>      END
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     Internal
                .LSTON
                .Page
                .FIN

Bank_Ret:
                Push    Flags
                Push    Rp
                Srp     #Wrk_Sys2
                
                Ld      !r1,Spl ;get location of return adr
                Add     !r1,#2  ;account for the 2 pushes at entry of routine
                Ld      !r0,@!r1
                Call    LookUp_Rom

                Pop     Rp
                Pop     Flags
                Ret
                
                .LSTOFF
                
