|
|
DataMuseum.dkPresents historical artifacts from the history of: Bogika Butler |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Bogika Butler Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 8064 (0x1f80)
Types: TextFile
Names: »ZMNCPM.ZAS«
└─⟦63c65de3f⟧ Bits:30009789/_.ft.Ibm2.50007335.imd Mogens Pelles Zilog 80,000 / EOS projekt
└─⟦this⟧ »ZMNCPM.ZAS«
;
; Z-8000 Portion of ZEX, V1.1 (CP/M Version)
;
; Copyright 1981 Western Wares, Norwood, CO 81423
;
;
; Set up for either the z8001 or z8002
;
$INCLUDE 'SYM.LIB'
Z8001 := FALSE
IF Z8001
$SEGMODULE Z8001_MONITOR
$TITLE 'Z-8001 Run Time Monitor - Version 1.1'
ELSE
$MODULE Z8002_MONITOR
$TITLE 'Z-8002 Run Time Monitor - Version 1.1'
ENDIF
;
; Z-8000 run time monitor for ZEX.
;
$include 'ZEXCP.LIB'
;
; PSA constants
;
IF Z8001
PSA_ENTRY_SIZE := 8
ELSE
PSA_ENTRY_SIZE := 4
ENDIF
INITIAL_FCW := %4000 ; FCW for user programs: System mode,
; non-segmented.
TRAP_FCW := %4000 ; FCW for all traps & interrupts
$eject
$PSECT ZMON NONSEG
;
; Should be origined by ZLK
; at location 'ZMON' within ZEX.COM
; This program is vectored to from location 'ZTPA'
; The Z-8000 is running in system, non-segmented mode.
;
; Initialization
;
LDA R15, SYSTEM_STACK ; Set stack pointer
;
; Set up the Program Status Area
;
LDA R3, START_OF_PSA
LD @R3, #TRAP_FCW ; Fill PSA with TRAP_FCW
LDA R2, START_OF_PSA+2
LD R1, #(VI_HANDLERS - START_OF_PSA)/2 - 1 ; Count
LDIR @R2, @R3, R1
LDA R2, START_OF_PSA+(2*PSA_ENTRY_SIZE - 2)
IF Z8001
LD @R2, #OFFSET BAD_INSTRUCTION
ELSE
LD @R2, #BAD_INSTRUCTION
ENDIF
INC R2, #PSA_ENTRY_SIZE
IF Z8001
LD @R2, #OFFSET PRIV_INSTRUCTION
ELSE
LD @R2, #PRIV_INSTRUCTION
ENDIF
INC R2, #PSA_ENTRY_SIZE
IF Z8001
LD @R2, #OFFSET SYSTEM_CALL
ELSE
LD @R2, #SYSTEM_CALL
ENDIF
INC R2, #PSA_ENTRY_SIZE
IF Z8001
LD @R2, #OFFSET SEGMENT_TRAP
ENDIF
INC R2, #PSA_ENTRY_SIZE
IF Z8001
LD @R2, #OFFSET NMI_HANDLER
ELSE
LD @R2, #NMI_HANDLER
ENDIF
INC R2, #PSA_ENTRY_SIZE
IF Z8001
LD @R2, #OFFSET NVI_HANDLER
ELSE
LD @R2, #NVI_HANDLER
ENDIF
LDA R2, VI_HANDLERS
LD R1, #(END_OF_PSA - VI_HANDLERS)/2 ; Count
IF Z8001
LDB RH3, # SEG START_OF_PSA ; PSA Segment number
SETB RH3, #7 ; Form a long address
LDB RL3, #0
ENDIF
FILL_VI_VECTORS:
IF Z8001
LD @R2, R3
INC R2, #2
DEC R1
LD @R2, #OFFSET VI_HANDLER
ELSE
LD @R2, #VI_HANDLER
ENDIF
INC R2, #2
DJNZ R1, FILL_VI_VECTORS
IF Z8001
;
; Set up the segment pointers in the first part of the PSA
;
LDA R2, START_OF_PSA + PSA_ENTRY_SIZE + 4
LDB RH1, #6
FILL_PSA_SEGMENTS:
LD @R2, R3 ; R3 = ((SEG START_OF_PSA) SHL 8) LOR %8000
INC R2, #PSA_ENTRY_SIZE
DBJNZ RH1, FILL_PSA_SEGMENTS
ENDIF
LDA R1, START_OF_PSA ; Set up PSA pointer register
LDCTL PSAPOFF, R1
IF Z8001
LDCTL PSAPSEG, R3
ENDIF
;
; Fetch the Entry Point and start the user's program running
; The program begins running in the current segment
; with execution determined by 'INITIAL_FCW'
;
CLR USERSC ; Clear the user SC routine address
LD R1, ENTRYP+2 ; Get the non-segmented entry
TEST R1 ; Is an entry there?
JR NZ,ENTRY_SET
LD R1, #ZTPA+6 ; Start at first location
ENTRY_SET:
PUSH @R15, R1 ; New PC
PUSH @R15, #INITIAL_FCW ; Starting FCW
LDPS @R15 ; Transfer control to user
;
; System Call Processor
;
SYSTEM_CALL:
LDM REG_BUF, R0, #16 ; Store all the registers
LDB RL7, R15(#1) ; Retrieve SC number
CPB RL7, #MAX_SC_NUMBER
JR LE,SC_NUMBER_OK
;
; System Call number too big,
; Check to see if the user has assigned a system
; call processor routine & go there if so.
;
LD R7,USERSC ; The user will modify this.
TEST R7
JP NZ, @R7 ; Go there if defined
BAD_SC:
;
; Illegal System Call
;
LDA R1, BAD_SC_MSG
CALR CONSOLE_MESSAGE
JR HOST_EXIT
SC_NUMBER_OK:
CLRB RH7 ; Form a 16-bit offset in R7
ADD R7,R7
LD R8,SC_FUNCTIONS(R7)
JP @R8 ; Jump to appropriate handler
;
; System Call Handlers
;
SC_FUNCTIONS:
IF Z8001
DW OFFSET BAD_SC,OFFSET BAD_SC,OFFSET BAD_SC,OFFSET BAD_SC,OFFSET BAD_SC
DW OFFSET ZAB_LOAD, OFFSET CALL_BDOS, OFFSET HOST_EXIT
ELSE
DW BAD_SC, BAD_SC, BAD_SC, BAD_SC, BAD_SC
DW ZAB_LOAD, CALL_BDOS, HOST_EXIT
ENDIF
MAX_SC_NUMBER := (. - SC_FUNCTIONS) SHR 1 - 1 ; Max system call processed by ZMON
ZAB_LOAD:
;
; SC #5: Load absolute object file
; R1 points to the filename ("d:filename.ext")
; RL0 = TRUE if ZEX should reinitialize the Z-8000
; and automatically begin executing the new file
;
LD REGBC, R1 ; Pass pointer to host in BC
LDB REGE, RL0 ; Store flag in host's E
LDB ZCODE, #ZLOAD ; Host function
CALR TO_HOST
LDB RL0, REGA ; Get success/failure
;
; Return from a System Call, Restore registers
;
SC_EXIT:
LDM R1, REG_BUF + 2, #15
IRET ; Return to caller
;
; SC #6: Direct host CPU to call BDOS
; RL0 = BDOS Function
; R1 = to host's DE (data pointer)
;
CALL_BDOS:
LDB REGC, RL0 ; Store function
LD REGDE, R1 ; Store data pointer
LDB ZCODE, #HOSTOS ; Host function: call BDOS
CALR TO_HOST ; Do it.
LDB RL0, REGA ; Get return value
JR SC_EXIT
;
; SC #7: Host exit via a warm boot
;
HOST_EXIT:
LDB ZCODE, #HEXIT ; Host exit
TO_HOST:
LD R13,HOSTZ ; Get patched routine address
CALL @R13 ; Call it to switch to host CPU
RET ; Return when reawakened
;
; Utility Routines
;
CONSOLE_MESSAGE:
LD REGDE, R1 ; Message address
LDB REGC, #MSG ; BDOS function
LDB ZCODE, #HOSTOS
CALR TO_HOST
RET
CONSOLE_OUT:
LDB REGC, #COT ; Console out function to BDOS
LDB REGE, RL1 ; Character to output
LDB ZCODE, #HOSTOS ; Call BDOS
CALR TO_HOST
RET
HEXOUT:
;
; Output R1 in hex to the console, preceeded by a space
;
LD R7, R1 ; Save value in R7
LDB RL1, #' ' ; Type a space first
CALR CONSOLE_OUT
;
; Convert R7 to hex ASCII and output
;
LDB RH2, RH7 ; Upper byte first
CALR OUT_HEX_BYTE
LDB RH2, RL7 ; Then lower byte
OUT_HEX_BYTE:
RLDB RL2, RH2 ; Rotate high nibble into low
CALR OUT_HEX_NIBBLE
RLDB RL2, RH2 ; Get low nibble back
OUT_HEX_NIBBLE:
ANDB RL2, #%0F ; Mask off high nibble
CPB RL2, #10
JR ULT,NO_ADD
INCB RL2, #7 ; Add seven to map 10 to 'A'
NO_ADD: ADDB RL2, #'0' ; To ASCII
LDB RL1, RL2 ; Type the character
CALR CONSOLE_OUT
RET
$eject
;
; Default trap handlers
;
BAD_INSTRUCTION:
;
; An illegal instruction was fetched by the CPU
; Abort with error message to console
;
LDA R1, BAD_INS_MSG
INSTRUCTION_TRAP:
CALR CONSOLE_MESSAGE
LD R1, @R15 ; R1 = Bad instruction
CALR HEXOUT
LD R1, R15(#4) ; Get PC in error
CALR HEXOUT
JR HOST_EXIT
$DSECT ZMON_MESSAGES
BAD_INS_MSG:
DB CR,LF,'Unimplemented Code:$'
$PSECT ZMON NONSEG
PRIV_INSTRUCTION:
;
; Priviledged instruction trap
;
LDA R1, PRIV_INS_MSG
JP INSTRUCTION_TRAP
$DSECT ZMON_MESSAGES
PRIV_INS_MSG:
DB CR,LF,'Priviledged Instruction Trap:$'
IF Z8001
$PSECT ZMON NONSEG
SEGMENT_TRAP:
;
; Segment Trap
;
LDA R1, SEGT_MSG
JP INSTRUCTION_TRAP
$DSECT ZMON_MESSAGES
SEGT_MSG:
DB CR,LF,'Segment Trap:$'
ENDIF
$PSECT ZMON NONSEG
NMI_HANDLER:
;
; Non maskable interrupt handler
;
LDA R1, NMI_MSG
JP INSTRUCTION_TRAP
$DSECT ZMON_MESSAGES
NMI_MSG:
DB CR,LF,'Non-maskable Interrupt:$'
$PSECT ZMON NONSEG
NVI_HANDLER:
;
; Non vectored interrupt handler
;
LDA R1, NVI_MSG
JP INSTRUCTION_TRAP
$DSECT ZMON_MESSAGES
NVI_MSG:
DB CR,LF,'Non-vectored Interrupt:$'
$PSECT ZMON NONSEG
VI_HANDLER:
LDA R1, VI_MSG
JP INSTRUCTION_TRAP
$DSECT ZMON_MESSAGES
VI_MSG: DB CR,LF,'Vectored Interrupt:$'
BAD_SC_MSG: DB CR,LF,'Illegal Z-8000 System Call$'
$DSECT ZMON_REGISTER_BUFFER
REG_BUF: DS 32 ; Store registers
;
; This size of the above code should be small enough to fit
; below the PSA.
;
$DSECT ZMON_PSA
;
; Program Status Area
;
START_OF_PSA:
DS 8*PSA_ENTRY_SIZE - PSA_ENTRY_SIZE/2 ; Trap & Interrupt vectors
VI_HANDLERS:
DS PSA_ENTRY_SIZE/2 * 256 ; 256 vectors, filled by ZMON
END_OF_PSA:
;
; System Stack
;
SYSTEM_STACK_SIZE := (ENTRYP - PSA) - (END_OF_PSA - START_OF_PSA)
; Rest of ZEX area for stack
DS SYSTEM_STACK_SIZE
SYSTEM_STACK:
END
«eof»