ROOT    TITLE   "Z80 BCPL Run Time System  -  Root"
        GET     "HEADER"
        LAYOUT
;  Root of the Z80 BCPL System for the IDW machine.  This section defines the
;  low store (EPROM) code, and its relationship to the RAM.
        LAYOUT
        REF     BCPL
        REF     RST38
        REF     GLOBIN

        DEF     ROOT
        DEF     MEMHI
        DEF     MEMLO

E.RST00 EQU     0
E.RST08 EQU     1
E.RST10 EQU     2
E.RST18 EQU     3
E.RST20 EQU     4
E.RST28 EQU     5
E.RST30 EQU     6
E.RST38 EQU     7
E.NMI   EQU     8

EPROMB  EQU     #X0000                  ;  Base of Eprom
EPROME  EQU     #X2000                  ;  End of Eprom

EP.CMD  EQU     #X00                    ;  Address of Eprom device
EP.ON   EQU     #X00                    ;  Command to switch Eprom on
EP.OFF  EQU     #X01                    ;  Command to switch Eprom off
        LAYOUT
;  Register Dump Area
;  ------------------


R.HL    EQU     EPROME+0                ;  Dump of HL
R.DE    EQU     EPROME+2                ;  Dump of DE
R.BC    EQU     EPROME+4                ;  Dump of BC
R.AF    EQU     EPROME+6                ;  Dump of AF

R.HL.   EQU     EPROME+8                ;  Dump of HL'
R.DE.   EQU     EPROME+10               ;  Dump of DE'
R.BC.   EQU     EPROME+12               ;  Dump of BC'
R.AF.   EQU     EPROME+14               ;  Dump of AF'

R.IX    EQU     EPROME+16               ;  Dump of IX
R.IY    EQU     EPROME+18               ;  Dump of IY

R.SP    EQU     EPROME+20               ;  Dump of SP
R.PC    EQU     EPROME+22               ;  Dump of PC

DBIX    EQU     EPROME+24               ;  Stack pointer for DEBUG
DBIY    EQU     EPROME+26               ;  Global vector for DEBUG
DBSP    EQU     EPROME+28               ;  Z80 stack pointer for DEBUG
        LAYOUT
;  DEBUG stack and global vector
;  -----------------------------


DBBASE  EQU     EPROME+30               ;  Base of DEBUG work area

DBGSIZE EQU     200*2                   ;  Size of DEBUG global vector
DBSSIZE EQU     200*2                   ;  Size of DEBUG stack

DBGV    EQU     DBBASE                  ;  Base of DEBUG global vector
DBSK    EQU     DBGV+DBGSIZE            ;  Base of DEBUG stack
DBZS    EQU     DBSK+DBSSIZE+20         ;  Base of DEBUG Z80 stack
        LAYOUT
;  Equates defining the Heap
;  -------------------------


HPBASE  EQU     DBZS+20                 ;  First free RAM location

MEMLO   EQU     HPBASE                  ;  Base of Heap memory
MEMHI   EQU     #XFFFE                  ;  Top of Heap memory

MEMSIZE EQU     MEMHI-MEMLO-2           ;  Size of available memory
MEMFLAG EQU     #X0001                  ;  Flag to mark the end of memory

STACK   EQU     MEMLO                   ;  Base of Z80 stack
        LAYOUT
        ABSOLUTE

        ORG     #X0000                  ;  RST #X00  and  RESET
        JP      RST00                   ;  Enter handler

        ORG     #X0008                  ;  RST #X08
        JP      RST08                   ;  Enter handler

        ORG     #X0010                  ;  RST #X10
        JP      RST10                   ;  Enter handler

        ORG     #X0018                  ;  RST #X18
        JP      RST18                   ;  Enter handler

        ORG     #X0020                  ;  RST #X28
        JP      RST20                   ;  Enter handler

        ORG     #X0028                  ;  RST #X20
        JP      RST28                   ;  Enter handler

        ORG     #X0030                  ;  RST #X30
        JP      RST30                   ;  Enter handler

        ORG     #X0038                  ;  RST #X38
        JP      RST38                   ;  Enter handler
        
        ORG     #X0066                  ;  NMI
        JP      NMI                     ;  Enter handler
        LAYOUT
;  RST00
;  -----
;
;    We enter here on restart.  We should set up the heap memory.  Then, we
;    must initialise the Stack, Global vector and Z80 stack for DEBUG.
;    Having done that, we can enter the BCPL module.

RST00   LD      HL,MEMSIZE              ;  First memory element
        LD      (MEMLO),HL              ;  Store it
        LD      HL,MEMFLAG              ;  Lase memory element
        LD      (MEMHI),HL              ;  Store it

        LD      HL,DBSK                 ;  Address of debug stack
        LD      DE,DBSK+1               ;  Next location address
        LD      BC,DBSSIZE-1            ;  Number of bytes to initialise
        LD      (HL),0                  ;  Value to be initialised
        LDIR                            ;  Initialise the stack

        LD      HL,DBGV                 ;  Address of debug global vector
        LD      DE,DBGV+1               ;  Next location address
        LD      BC,DBGSIZE-1            ;  Number of bytes to initialise
        LD      (HL),0                  ;  Value to be initialised
        LDIR                            ;  Initialise the global vector

        LD      HL,DBGSIZE/2            ;  Size of global vector
        LD      (DBGV),HL               ;  Store in global vector

        LD      IX,DBSK+128             ;  Base of debug stack
        LD      IY,DBGV+128             ;  Base of debug global vector
        LD      SP,DBZS                 ;  Base of debug Z80 stack

        LD      HL,ROOT                 ;  Root of BCPL modules
        CALL    GLOBIN                  ;  Initialise the global vector

        LD      HL,E.RST00              ;  Load reason code
        EXX                             ;  Swap register sets
        LD      L,(IY-120)              ;  Low byte of "debug"
        LD      H,(IY-119)              ;  High byte of "debug"
        APPLY                           ;  Call debug
        DEFB    0                       ;  Increase in stack size
        
        LD      (DBIX),IX               ;  Save debug's IX
        LD      (DBIY),IY               ;  Save debug's IY
        LD      (DBSP),SP               ;  Save debug's SP

;  We are now at the point where we can start running the main program.  We
;  should copy ourselves from EPROM to RAM, and then enter the main program.

        LD      HL,0                    ;  Starting address in EPROM
        LD      DE,0                    ;  Starting address in RAM
        LD      BC,EPROME-EPROMB        ;  Size of the EPROM
        LDIR                            ;  Copy from EPROM to RAM

        LD      A,EP.OFF                ;  Eprom off command
        OUT     (EP.CMD),A              ;  Write the command

        LD      SP,STACK                ;  Set up Z80 stack pointer

        JP      BCPL                    ;  Enter BCPL module
        LAYOUT
;  Exception Handlers
;  ------------------
;
;    Handlers for all the exceptions which are not trapped by the system.


RST08   LD      (R.SP),SP               ;  Save stack pointer
        LD      SP,(DBSP)               ;  Load DEBUG stack pointer
        CALL    ERROR                   ;  Call error handler
        DEFB    E.RST08                 ;  Error code


RST10   LD      (R.SP),SP               ;  Save stack pointer
        LD      SP,(DBSP)               ;  Load DEBUG stack pointer
        CALL    ERROR                   ;  Call error handler
        DEFB    E.RST10                 ;  Error code


RST18   LD      (R.SP),SP               ;  Save stack pointer
        LD      SP,(DBSP)               ;  Load DEBUG stack pointer
        CALL    ERROR                   ;  Call error handler
        DEFB    E.RST18                 ;  Error code


RST20   LD      (R.SP),SP               ;  Save stack pointer
        LD      SP,(DBSP)               ;  Load DEBUG stack pointer
        CALL    ERROR                   ;  Call error handler
        DEFB    E.RST20                 ;  Error code


RST28   LD      (R.SP),SP               ;  Save stack pointer
        LD      SP,(DBSP)               ;  Load DEBUG stack pointer
        CALL    ERROR                   ;  Call error handler
        DEFB    E.RST28                 ;  Error code


RST30   LD      (R.SP),SP               ;  Save stack pointer
        LD      SP,(DBSP)               ;  Load DEBUG stack pointer
        CALL    ERROR                   ;  Call error handler
        DEFB    E.RST30                 ;  Error code


NMI     LD      (R.SP),SP               ;  Save stack pointer
        LD      SP,(DBSP)               ;  Load DEBUG stack pointer
        CALL    ERROR                   ;  Call error handler
        DEFB    E.NMI                   ;  Error code
        LAYOUT
;  ERROR
;  -----
;
;    Default error handler.  Dump the registers in fixed memory, and call
;    debug.  The SP register has already been dumped.


ERROR   LD      (R.HL),HL               ;  Save HL
        LD      (R.DE),DE               ;  Save DE
        LD      (R.BC),BC               ;  Save BC
        EXX                             ;  Switch register sets
        LD      (R.HL.),HL              ;  Save HL'
        LD      (R.DE.),DE              ;  Save DE'
        LD      (R.BC.),BC              ;  Save BC'

        PUSH    AF                      ;  Get AF into ...
        POP     HL                      ;  ... a reasonable register
        LD      (R.AF),HL               ;  Save AF
        EX      AF,AF'                  ;  Switch to alternate AF
        PUSH    AF                      ;  Get AF' into ...
        POP     HL                      ;  ... a reasonable register
        LD      (R.AF.),HL              ;  Save AF'

        LD      HL,(R.SP)               ;  Load old stack pointer
        LD      E,(HL)                  ;  Low byte of PC
        INC     HL                      ;  Increment pointer
        LD      D,(HL)                  ;  High byte of PC

        LD      (R.PC),DE               ;  Save PC
        LD      (R.IX),IX               ;  Save IX
        LD      (R.IY),IY               ;  Save IY

;  We have now dumped all the registers.  The return address on the stack
;  points to a byte reason code for the error.  We pass this on to debug
;  without change.  After calling debug, we must restore the registers and
;  return to the program.

        LD      IX,(DBIX)               ;  Load debug stack pointer
        LD      IY,(DBIY)               ;  Load debug global vector

        POP     HL                      ;  Get pointer to reason code
        LD      L,(HL)                  ;  Load low byte
        LD      H,0                     ;  Load high byte
        EXX                             ;  Swap register sets
        LD      L,(IY-120)              ;  Low byte of "debug"
        LD      H,(IY-119)              ;  High byte of "debug"
        APPLY                           ;  Call debug
        DEFB    0                       ;  Increase in stack size

        LD      (DBIX),IX               ;  Save debug's IX
        LD      (DBIY),IY               ;  Save debug's IY
        LD      (DBSP),SP               ;  Save debug's SP
        
        LD      HL,(R.AF.)              ;  Load AF'
        PUSH    HL                      ;  Save on stack
        POP     AF                      ;  Set up AF'

        LD      HL,(R.HL.)              ;  Load HL'
        LD      DE,(R.DE.)              ;  Load DE'
        LD      BC,(R.BC.)              ;  Load BC'

        EXX                             ;  Swap to the ...
        EX      AF,AF'                  ;  ... main register set

        LD      HL,(R.AF)               ;  Load AF
        PUSH    HL                      ;  Save on stack
        POP     AF                      ;  Set up AF

        LD      HL,(R.HL)               ;  Load HL
        LD      DE,(R.DE)               ;  Load DE
        LD      BC,(R.BC)               ;  Load BC

        LD      IX,(R.IX)               ;  Load IX
        LD      IY,(R.IY)               ;  Load IY
        LD      SP,(R.SP)               ;  Load SP
        RET                             ;  Load PC, and return
        LAYOUT
        ALIGN

ROOT                                    ;  Start of other BCPL modules
        END


