DataMuseum.dk

Presents historical artifacts from the history of:

Bogika Butler

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Bogika Butler

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download

⟦f9e8fbd16⟧ TextFile

    Length: 8064 (0x1f80)
    Types: TextFile
    Names: »ZMNCPM.ZAS«

Derivation

└─⟦63c65de3f⟧ Bits:30009789/_.ft.Ibm2.50007335.imd Mogens Pelles Zilog 80,000 / EOS projekt
    └─⟦this⟧ »ZMNCPM.ZAS« 

TextFile

;
;  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»