;==============================================================
;                 RUNSOLOS by Martin Eberhard
;                      a PTDOS Utility
;
;             Runs Solos/Cuter programs under PTDOS
;
; Usage: RUNSOLOS <filename>
;
; <filename> must be a single-segment PTDOS Image file. If it
; contains an execution address, then the program will be
; loaded and executed. If not, then the program will be loaded,
; and control will return to PTDOS.
;
; On entry, Solos/Cuter programs may expect the following:
;  1. hl = the address of the Solos/Cuter jump table
;     (This table must be aligned with a 256-byte page.)
;  2. A return address to Solos/Cuter is on the stack
;  3. (SP-2) contains the called program's address (which
;     could be used by a self-relocating program).
;  4. The stack has room for a reasonable number of PUSHes
;
; RunSolos provides a Solos/Cuter-like jump table, which just
; jumps to the expected Solos/Cuter rountine for all cases
; except the warm-start entry (RETRN), which will return to
; PTDOS instead. (Note that the cold-start entry (INIT) jumps
; to Solos/Cuter.)
;
; hl points to this jump table when the requested Solos/Cuter
; program is run.
;
; The return address on the stack will return to RunSolos,
; which will return to PTDOS. The requested program's address
; is in the correct (SP-2) position.
;
; RunSolos will abort with an error message for any of the
; following conditions:
;  1. The requested program is not an Image file
;  2. The Image file appears to have more than 1 segment
;     (or other junk at the end of the Image file)
;  3. Neither Solos nor Cuter can be found at the standard
;     C000 address
;  4. Bogus input on the command line
;  5. Any PTDOS disk error
;
;==============================================================
; Revision History
;
; 1.00  26 February 2015  M.Eberhard
;   Created
; 1.01  10 April 2015  M. Eberhard
;   Compact code. Tell PTDOS to send level 1 & 2 errors back to
;   us. Print help screen if no Image file name given. Move the
;   jump table and reset code into USARE so Solos cassette tape
;   operations won't wipe it out.
;==============================================================
; NOTES
;
; RunSolos runs in Solos's buffer memory and User Area. This
; precludes its use with any PTDOS device drivers that require
; this memory space.
;
; RunSolos assumes that Solos or Cuter is at the standard
; address of C000h. If a Solos-like jump table is not found
; at this address, then RunSolos will abort.
;
; RunSolos also assumes that the program that is being run does
; not clobber PTDOS (which is above about 8000h), or RunSolos's
; jump table and reset code (which is in Solos's User Area).
;
; The jump table and the RSRTRN code must be within Solos's
; User Area (USARE), so that cassette tape operations do not
; wipe them out. (Note that Solos's stack grows downward into
; this area.) Additionally, the jump table must be on a page
; boundary. This means that it must be at CB00h, the only page
; boundary within the User Area. Some code arrangement is
; required to meet these requirements without a lot of waste.
;
; Written to assemble with Digital Research's ASM
;==============================================================

FALSE	equ	0
TRUE	equ	not FALSE

;----------------
;ASCII Characters
;----------------
CR	equ	0Dh		;carriage return
LF	equ	0Ah		;Linefeed
VT	equ	0Bh		;VDM clear screen
QUOTE	equ	27H		;single quote
MODE	equ	80h		;Sol-20 Mode Select key
ESC	equ	1Bh		;Escape

;------------------------------------
;CUTER/SOLOS Equates and Entry Points
;------------------------------------
CUTID:	equ	7Fh		;in byte 0 of Cuter

SOLOS	equ	0C000h		;Solos/Cuter base address
SOLID	equ	SOLOS+00h	;00 for solos, 7Fh for Cuter
INIT	equ	SOLOS+01H	;Cold-start SOLOS
RETRN	equ	SOLOS+04H	;Return control to SOLOS
FOPEN	equ	SOLOS+07h	;Open cassette tape file
FCLOS	equ	SOLOS+0Ah	;Close cassette tape file
RDBYT	equ	SOLOS+0Dh	;Read one cassette tape byte
WRBYT	equ	SOLOS+10h	;Write one cassette tape byte
RDBLK	equ	SOLOS+13h	;Read one cassette tape block
WRBLK	equ	SOLOS+16h	;Write one cassette tape block
SOUT	equ	SOLOS+19H	;Write b to current pseudoport
AOUT	equ	SOLOS+1CH	;Write b to pseudoport a
SINP	equ	SOLOS+1FH	;Read current pseudoport into a
AINP	equ	SOLOS+22H	;Read from pseudoport a into a

FBUF1	equ	SOLOS+0863h	;Tape header buffer. All RAM
				;past here is available
USARE	equ	SOLOS+0AB4h	;User area in SOLOS RAM

;---------------
;Program Equates
;---------------
RSBASE	equ	FBUF1		;Runs in Solos RAM area
JMPTBL	equ	SOLOS+0B00h	;page-aligned jump table
STACK	equ	SOLOS+0C00h	;end of Solos RAM

;-----------------------------
;PTDOS definitions from PTDEFS
;-----------------------------
; 1) MAIN ENTRY POINTS  (EP AREA)

SYS	equ	0BCBCh
RB	equ	SYS-3	;READ SINGLE BYTE
WB	equ	SYS-6	;WRITE SINGLE BYTE
UTIL	equ	SYS-9	;UTILITY HANDLER
RESET	equ	SYS-12	;RESET TO SYSTEM
ERRL0	equ	SYS-15	;ERROR LEVEL 0 RETURN FROM DRIVER
ERRL1	equ	SYS-18	;ERROR LEVEL 1 RETURN FROM DRIVER
ERRL2	equ	SYS-21	;ERROR LEVEL 2 RETURN FROM DRIVER
SYSGLO	equ	SYS-23	;POINTER TO SYSTEM GLOBAL AREA
CONIN	equ	SYS-26	;CONSOLE INPUT ONE CHARACTER
CONOUT	equ	SYS-29	;CONSOLE OUTPUT ONE CHARACTER
CONTST	equ	SYS-32	;CONSOLE INPUT READY TEST
PSCAN	equ	SYS-35	;PARAMETER SCANNER ENTRY
INTDN	equ	SYS-38	;INTERRUPT DONE ENTRY POINT
INTDK	equ	SYS-41	;INTERRUPT PROCESSING ENTRY

; 2) SYS CALL OPERATIONS  (CODE FOR OPERATION BYTE)

CREOP	equ	0	;CREATE FILE  (DE -> PARMS)
OPEOP	equ	1	;OPEN FILE  (DE -> NAME, HL = BUFF OPT)
KILOP	equ	2	;KILL FILE  (DE -> NAME)
RBLOP	equ	3	;READ BLOCK OF DATA
WBLOP	equ	4	;WRITE BLOCK OF DATA
SPAOP	equ	5	;MOVE FILE CURSOR
EOFOP	equ	6	;ENDFILE A FILE
CLOOP	equ	7	;CLOSE A FILE
CHTOP	equ	8	;CHANGE TYPE OF FILE
CHAOP	equ	9	;CHANGE ATTRIBUTES OF A FILE
CHNOP	equ	10	;CHANGE NAME OF A FILE
INFOP	equ	11	;GET INFO ABOUT A FILE
SUNOP	equ	12	;SET DEFAULT UNIT
RETOP	equ	13	;RETURN TO CI
RESOP	equ	14	;RESET
ABTOP	equ	15	;ABORT, THEN RETURN TO CI
SEKOP	equ	16	;SET FILE CURSOR TO THIS POINT (SEEK)
RNDOP	equ	17	;MAKE FILE RANDOMLY ACCESSIBLE
CAOP 	equ	18	;CLOSE ALL FILES (OR ALL ON A UNIT)
CTLOP	equ	19	;CONTROL/STATUS OF DRIVER
SREOP	equ	20	;SHORT RESET TO CI
DRDOP	equ	21	;DELIMITED READ
DWROP	equ	22	;DELIMITED WRITE
DSPOP	equ	23	;DELIMITED SPACE
RTROP	equ	24	;RETURN AND SET TRAP

; 3) FILE PROTECTION ATTRIBUTES

PKIL	equ	1	;DELETE PROTECT
PWRI	equ	2	;WRITE PROTECTION
PREA	equ	4	;READ PROTECTION
PFINF	equ	8	;INFORMATION PROTECT (FILES WON'T LIST)
PATR	equ	10h	;ATTRIBUTE CHANGE PROTECTION
PNAT	equ	20h	;NAME AND TYPE CHANGE PROTECTION
PALO	equ	40h	;DISK ALLOCATION PROHIBITION
PUSR	equ	80h	;USER ATTRIBUTE

; 4) SYSTEM GLOBAL AREA

SGA	equ	0	;System Global Area base
GLCIF	equ	SGA	;CI INPUT FILE #
GLCOF	equ	SGA+1	;CI OUTPUT FILE #
GLUTF	equ	SGA+2	;UTILITY FILE #
GLECF	equ	SGA+3	;CI ECHO FILE #
GLUNI	equ	SGA+4	;DEFAULT UNIT #
GLPRM	equ	SGA+5	;# OF PERMANENTLY OPEN FILES
GLMXU	equ	SGA+6	;MAX UNIT NUMBER (= # DRIVES+1)
GLSWI	equ	SGA+7	;SYSTEM SWITCHES
GLERS	equ	SGA+9	;SOFT (LEVEL 2) ERROR WORD
GLERM	equ	SGA+11	;MODERATE (LEVEL 1) ERROR WORD
GLERH	equ	SGA+13	;HARD (LEVEL 0) ERROR WORD
GLTRP	equ	SGA+15	;CI RETURN TRAP WORD
GLPRO	equ	SGA+17	;USER MEMORY PROTECT WORD
GLFLG	equ	SGA+19	;CHARACTER WAITING FLAG
GLBYT	equ	SGA+20	;THE CHARACTER
GLRCH	equ	SGA+21	;FILE #0 READ CHRR ROUTINE POINTER
GLWCH	equ	SGA+23	;FILE #1 WRITE CHR ROUTINE POINTER
GLTCH	equ	SGA+25	;CONSOLE TEST CHR READY ROUTINE PTR
GLNCT	equ	SGA+27	;NULL COUNT FOLLOWING CR
GLVER	equ	SGA+28	;SYSTEM VERSION
GLDAT	equ	SGA+29	;DATE (MM,DD,YY)
GLNAM	equ	SGA+32	;DISK NAME (8 ASCII CHARACTERS)
GLPAS	equ	SGA+40	;PASSWORD
GLBD1	equ	SGA+48	;WAIT FOR INTERRUPT ROUTINE ADDRESS
GLBD2	equ	SGA+50	;RESERVED FOR FUTURE USE
GLIF1	equ	SGA+52	;INTERRUPT ENABLE FLAG
GLIF2	equ	SGA+53	;DISK INT PROCESSING COMPLETE FLAG
GLLOW	equ	SGA+54	;LOW ADDRESS OF BUFFER AREA
GLECH	equ	SGA+56	;ECHO DISABLE SWITCH
GLLOK	equ	SGA+57	;DISK WRITE LOCK SWITCH
GLUPS	equ	SGA+58	;UPSHIFT SWITCH
GLRBC	equ	SGA+59	;READ-BACK CHECK SWITCH
GLBIO	equ	SGA+60	;BINARY CONSOLE I/O SWITCH
GLLOG	equ	SGA+61	;LOG FILE SWITCH
GLVRB	equ	SGA+62	;VERBOSE SWITCH
GLFTR	equ	SGA+63	;SWITCH RESERVED FOR FUTURE USE

; 6) CXBUF AND OLBUF

CXBUF	equ	0BCC0H	;COMMAND EXECUTION BUFFER
OLBUF	equ	0BDC0H 	;OVERLAY BUFFER

; 7) STATUS BITS IN USER DEVICE WORD

SBPRO	equ	1	;SETTABLE PROMPT MESSAGE
SBINT	equ	2	;INTERRUPT DRIVEN
SBATB	equ	4	;DOES ABSOLUTE TABS
SBFF	equ	8	;DOES FORM-FEEDS
SBSTB	equ	10h	;SETTABLE TABS
SBTAB	equ	20h	;DOES TAB'S (CONTROL-I)
SBIAT	equ	40h	;INTERACTIVE
SBDUP	equ	80h	;DUPLICATIVE

; 8)  ERROR NUMBERS

ERNEX	equ	1	;NONEXISTENT FILE
ERAEX	equ	2	;FILE ALREADY EXISTS
ERUFN	equ	3	;UNASSIGNED FILE NUMBER
ERPRO	equ	4	;PROTECTION VIOLATION
ERNIF	equ	5	;FILE NOT TYPE IMAGE
ERMOP	equ	6	;ILLEGAL OP ON MULTIPLY OPEN FILE
ERRAC	equ	7	;RANDOM ACCESS TO NON-RANDON FILE
ERRDV	equ	8	;RANDOM ACCESS TO DEVICE FILE
ERZBC	equ	9	;ZERO BLOCK COUNT IN DEVICE IMAGE FILE

ERIOP	equ	10	;ILLEGAL PTDOS OPERATION
ERIBF	equ	11	;ILLEGAL BUFFER ADDRESS
ERIBS	equ	12	;ILLEGAL BLOCK SIZE
ERINM	equ	13	;ILLEGAL CHARACTER IN NAME
ERICU	equ	14	;ILLEGAL CHARACTER IN UNIT
ERIUN	equ	15	;ILLEGAL UNIT
ERNTL	equ	16	;NAME TOO LONG
ERMEM	equ	17	;USER MEMORY PROTECT VIOLATION
ERSMP	equ	18	;SYSTEM MEMORY PROTECT VIOLATION
ERUCN	equ	19	;UNIT CONFLICT
ERIUP	equ	20	;ILLEGAL UTILITY OPERATION
ERDRI	equ	21	;DRIVER ERROR
ERIDA	equ	22	;ILLEGAL DRIVER ACCESS
ERNCT	equ	23	;DRIVER NOT PARTICIPATING IN THIS CTRL

EREOF	equ	24	;END OF FILE ENCOUNTERED (OR BOF)
ERSEK	equ	25	;SEEK ADDRESS OUT OF RANGE

ERTOP	equ	26	;TOO MANY FILES OPEN
ERMOV	equ	27	;MEMORY OVERFLOW
ERNID	equ	28	;NO FILE ID'S LEFT
ERDFL	equ	29	;DISK FULL
ERDIR	equ	30	;DIRECTORY FULL

ERFSB	equ	32	;FILE STRUCTURE BAD
ERFIC	equ	33	;FILE ID CONFLICT
ERBSC	equ	34	;BLOCK SIZE CONFLICT
ERSCC	equ	35	;SECTOR CONFLICT
ERCFS	equ	36	;CAN'T FIND SECTOR
ERCRC	equ	37	;CRC ERROR OR READ/WRITE ABORTS
ERCFT	equ	38	;CAN'T FIND TRACK
ERRBC	equ	39	;READ-BACK-CHECK FAILED
ERLOK	equ	40	;DISK IS WRITE LOCKED
ERXXX	equ	41	;CATESTROPHIC ERROR
ERSYN	equ	42	;COMMAND SYNTAX ERROR
ERNAX	equ	43	;NAME EXPECTED
ERNUX	equ	44	;FILE NUMBER EXPECTED
ERBCX	equ	45	;BYTE COUNT EXPECTED
ERADX	equ	46	;ADDRESS EXPECTED
ERVAX	equ	47	;VALUE EXPECTED
EROPX	equ	48	;OPTIONAL PARAMETER EXPECTED
ERINA	equ	49	;ILLEGAL FILE NAME
ERIFI	equ	50	;ILLEGAL FILE NUMBER
ERIAD	equ	51	;ILLEGAL ADDRESS
ERIBC	equ	52	;ILLEGAL BYTE COUNT
ERIVA	equ	53	;ILLEGAL VALUE
ERIOS	equ	54	;ILLEGAL OPTION SPECIFIER
ERITY	equ	55	;ILLEGAL TYPE
ERIAT	equ	56	;ILLEGAL ATTRIBUTES
ERRED	equ	57	;DRIVE NOT READY

; 9) PARAMETER SCANNER OPERATIONS

PSCO	equ	0	;CREATE IF NONE EXIST AND OPEN
PSOP	equ	1	;OPEN FILE
PSFCO	equ	2	;FORCE CREATE AND OPEN FILE
PSC	equ	4	;CREATE FILE IF NONE EXIST
PSN	equ	5	;READ NAME TO REG DE
PSFC	equ	6	;FORCE CREATE FILE
PSOPT	equ	8 	;READ ALL CHRS UNTIL , ; cr 0
PSV	equ	85H	;CONVERT VALUE INTO REG DE
PSONE	equ	0A5H	;READ SINGLE BYTE

;NOTE: ABOVE VALUES + 40H = USER INPUT BUFFER IN REG HL

PSCN	equ	0D5H	;CONVERT MY VALUE TO DE, BASE IN REG B

; 10) UTILITIES

UXOP	equ	0	;EXPLAIN ERROR
UXOP1	equ	1	;DATA FOR UXOP
UXOP2	equ	2	;DITTO, PART 2
UCAT	equ	3	;CATALOG ROUTINE

;======================
;= Start of Execution =
;======================
	org	RSBASE+30h

	lxi	sp,STACK		;create local stack

;--------------------------------------------------------
;Tell PTDOS to send level 1 and level 2 errors back to us
;--------------------------------------------------------
	lhld	SYSGLO		;find PTDOS's global variables
	lxi	d,GLERS
	dad	d		;hl=GLERS address

	lxi	d,4*256+0FFh	;4 bytes for 2 16-bit -1's
SERLUP:	mov	m,e		;(page 6-12)
	inx	h
	dcr	d
	jnz	SERLUP

;-------------------------------------------------
;Scan the program name from the command line
;(We can't use PSOP to scan and then open the
;file because PSOP does not return the file type.)
;-------------------------------------------------
	lxi	d,SCNBUF	;destination for name
	push	d
	mvi	a,PSOPT		;Scan one item
	call	PSCAN		;(page 6-10)
	jc	PSERR		;error if too many characters

	pop	d		;SCNBUF

;----------------------------------------------------
;If no file name or '?' then print help screen & exit
;----------------------------------------------------
	mov	a,c		;no file name?
	ora	a
	jz	HLPEXT		;y: help screen

	ldax	d		;look at 1st chr
	cpi	'?'		;asking for help?
	jz	HLPEXT		;y:give help

;---------------------------------------------------
;Check for Solos/Cuter by looking for the jump table
;and either the Solos or the Cuter ID byte
;---------------------------------------------------
	lxi	h,SOLOS		;Solos vs Cuter ID
	mov	a,m
	sta	FSOLID		;put it in our jump table

	ora	a		;Solos?
	jz	DETSOL

	cpi	CUTID		;Cuter?
	jnz	NOSOLS

DETSOL:	mvi	a,0C3h		;jmp opcode
	mvi	b,7		;should be 7 jumps

CHKSOL:	inx	h
	cmp	m
	jnz	NOSOLS		;no Solos found
	inx	h	
	inx	h
	dcr	b
	jnz	CHKSOL

;--------------------------------------------------------
;Open specified file and get its file number & file type.
;de=SCNBUF and the 0-terminated file name is at SCNBUF
;--------------------------------------------------------
	push	d		;SCNBUF
	lxi	h,0		;static buffering (page 5-7)
	call	SYS		;open the disk file
	db	OPEOP		;(page 7-12)
	call	PTDER		;Let PTDOS explain any error
	pop	d		;SCNBUF

;------------------------------------------------------------
;Abort with error if the specified file is not an Image file.
;a=FILENUM, the file number assigned by PTDOS
;b=the file type, from OPEOP
;de=SCNBUF
;------------------------------------------------------------
	inr	b		;don't mess up a
	dcr	b		;msb must be 0 for Image file
	jm	FTERR		;error if not

	sta	FILNUM		;remember assigned file number
	push	psw

;--------------------------------------------
;Load the image file's header to determine
;its size and load address.
;a=FILENUM, the file number assigned by PTDOS
;de=SCNBUF
;--------------------------------------------
	lxi	b,4		;4-byte header
	call	SYS
	db	RBLOP		;read the header
	call	PTDER		;Let PTDOS explain any error

;----------------------------------
;Load the image file's data payload
;into memory at its load address.
;----------------------------------
	pop	psw		;get FILNUM (assigned file #)
	push	psw
	lhld	BYTCNT		;byte count
	mov	b,h
	mov	c,l

	lhld	LODADR		;Image file load address
	xchg
	call	SYS
	db	RBLOP		;read the file
	call	PTDER		;Let PTDOS explain any error

;-----------------------------------------------------------
;Get the execution address from the end of the file, if it
;exists. The end of the file should contain either:
;  0 bytes (this is not an executable Image file)
;  2 bytes (These 2 bytes are the execution address)
;  4 bytes (This is a 0-byte segment. The first 2 bytes
;           must be 0, and the second 2 bytes are the
;           execution address)
; (page 5-8)
; Abort if there is anything further at the end of the file.
;-----------------------------------------------------------
	lxi	d,EXEADR	;where to put it
				;(past the other info)
	lxi	b,5		;5 bytes max
	lda	FILNUM		;get assigned file number
	call	SYS
	db	RBLOP		;read the header
	jmp	EHUNT2		;EOF detected?

	mvi	a,EREOF		;EREOF is an even number
	mov	c,a		;force JNKERR below

EHUNT2:	cpi	EREOF		;error due to EOF?
	jnz	PTDER		;n:let PTDOS explain error

;-------------------
;Close the file.
;-------------------
	push	b
	call	CLOSE
	pop	b

;--------------------------------------------------------------
;PTDOS RBLOP returns with c = the number of requested bytes
;that were NOT loaded. We requested PTDOS to load 5 bytes, so:
;  if c=5 then the file is not executable
;  if c=3 then it is a simple execution address
;  if c=1 then it is a 0-byte segment, with execution address
;  anything else is an error
;--------------------------------------------------------------
	xra	a		;clear carry
	mov	a,c		;5-bytes received

	rar	
	jnc	JNKERR		;all even numbers are bogus

;if c=2 then the file is not executable.
;if c=1 then it is a simple 2-byte execution address
;if c=0 then it is a 0-byte segment, with execution address

	lhld	EXEADR		;potential exec address	
	dcr	a
	jz	RUNPRG		;2-byte executable

	jp	NOEXE		;non-executable

	mov	a,h		;better be a 0-byte segment
	ora	l		;otherwise its junk
	jnz	JNKERR

	lhld	EXEADR+2	;exec address form 0-byte seg

;---------------------------------------------------
;This program is executable. Set up the stack and hl
; the way Solos likes them, and go run the program
;On Entry:
;  hl = execution address
;---------------------------------------------------
RUNPRG:	lxi	d,REXIT		;fake calling address
	push	d

	push	h		;program's execution address

	mvi	b,VT		;clear Solos's VDM screen
	call	SOUT

	lxi	h,FSTABL	;fake SOLOS jump table
	ret			;go execute loaded program

;***Subroutine*********************
;Close the disk file, if it is open
;On Entry:
;  FILNUM=file number
;trashes psw,hl
;**********************************
CLOSE:	lxi	h,FILNUM	;did we actually open a file?
	mov	a,m
	mvi	m,0		;don't get stuck here
	ora	a		;was a file open?
	rz

	call	SYS		;close file
	db	CLOOP		;(page 7-5)
	call	PTDER		;Let PTDOS explain any error
	ret

;***Exit*********************
;This file is not executable.
;Report and return to PTDOS
;****************************
NOEXE:	call	ILPRNT
	db	CR,LF+80h

	lhld	BYTCNT
	call	PHLHEX

	call	ILPRNT
	db	' byte data file loaded at',' '+80h

	lhld	LODADR
	call	PHLHEX

	jmp	REXIT

;***Exit*****************************************************
;Get PTDOS to explain a SYS error, close the open file,
;and return (with reset) to PTDOS
;(Pages 6-8 and 8-1)
;On Entry:
;  a = error code
;  top of stack = address of routine that generated the error
;************************************************************
PTDER:	sta	ERMCD		;Store error code for UTIL

	pop	h		;Get calling address
	dcx	h		;Back up and get SYS opcode
	dcx	h
	dcx	h
	dcx	h
	mov	a,m		;a=SYS opcode
	sta	COMCD		;Give SYS opcode to UTIL

	lxi	h,RSMSG		;'Called from' message
	mvi	a,82H		;UTIL ctrl word (see page 8-1)
				;Returns when done

	call	UTIL
	db	UXOP		;Explain error
	jmp	UERROR		;UTIL Error return
COMCD:	db	0FFh
ERMCD:	db	0FFh
				;UTIL normally returns here

UERROR:	call	CLOSE		;close the disk file
	jmp	REXIT

RSMSG:	db	'RUNSOLOS',0

;***Exit******************
;File is not an Image file
;*************************
FTERR:	call	CILPRT
	db	'Not a','n'+80h

;Fall into BADPRT

;***Exit******************
;Finish error message
;*************************
BADPRT:	call	ILPRNT
	db	' Image fil','e'+80h

	jmp	REXIT

;***Exit************
;Generic PSCAN Error
;*******************
PSERR:	call	CILPRT
	db	'Huh','?'+80h
	jmp	REXIT

;***Exit**************
;Solos/Cuter not found
;*********************
NOSOLS:	call	CILPRT
	db	'Solos not foun','d'+80h
	jmp	REXIT

;***Exit******************
;Junk at end of Image file
;*************************
JNKERR:	call	CILPRT
	db	'Ba','d'+80h

	jmp	BADPRT

;===Exit=====================================
;Print Help screen and exit to PTDOS
;(A Solos program's stack may wipe this out.)
;============================================
HLPEXT:	call	CILPRT
;    1234567890123456789012345678901234567890123456789012345678901234
 db 'RUNSOLOS 1.01 by Martin Eberhard'
 db CR,LF,LF
 db QUOTE,'RUNSOLOS <Image>',QUOTE
 db ' runs a Solos program stored as <Image> on'
 db CR,LF
 db 'disk. If the program returns, it will return to PTDOS','.'+80h

 jmp	REXIT

;======================
; Initialized Variables
;======================
FILNUM:	db	0	;file number

;================================================
;Scan buffer - up to 20 chrs with the file name
;load. Once the file has been opened, this buffer
;gets reused to load the file header info.
;(A Solos program's stack may wipe this out.)
;================================================
SCNBUF:
BYTCNT:	ds	2
LODADR:	ds	2
EXEADR:	ds	2
SCNDAT:	ds	14

;======================================================
;The following code is located in Solos's User Area,
;before the Jump table, which must be located at CB00h.
;======================================================
;----------------------------------
;Create an assembler error if the
;previous segment overlaps this one
;----------------------------------
S1END	equ	$

 if (USARE-S1END)/256
ERROR: SEGMENT OVERLAP
 endif

	org	USARE

;***Subroutine*************************************
;Print CR,LF, inline string
;The call to CILPRT is followed by an ASCII string.
;The last string byte has its msb set.
;trashes psw,b
;**************************************************
CILPRT:	call	ILPRNT
	db	CR,LF+80h

;Fall into ILPRNT

;***Subroutine*************************************
;Print inline string
;The call to ILPRNT is followed by an ASCII string.
;The last string byte has its msb set.
;trashes psw,b
;**************************************************
ILPRNT:	xthl			;Save hl, get msg addr

IPLOOP:	mov	a,m
	ani	7Fh		;strip end marker
	call	CONOUT		;print byte (trashes b)
	mov	a,m		;end?
	inx	h		;Next byte
	ora	a		;msb set?
	jp	IPLOOP		;Do all bytes of msg
	
	xthl			;Restore hl,
				;..get return address
	ret

;=====Subroutine==========================
;Print hl as 4 hex digits, followed by 'h'
;On Entry
;  hl = value to print
;Trashes psw,b
;=========================================
PHLHEX:	mov	a,h		;high byte 1st
	call	PAHEX
	mov	a,l		;then the low byte
	call	PAHEX

	mvi	a,'h'		;label it as hex

	jmp	CONOUT		;trashes b

;=====Subroutine========
;Print a as 2 hex digits
;On Entry
;  a = value to print
;Trashes psw,b
;=======================
PAHEX:	push	psw		;save digit
	rrc			;high nibble 1st
	rrc
	rrc
	rrc
	call	PHXNIB
	pop	psw		;recover low nibble

;fall into PHXNIB

;----------------------------------------
;local subroutine to print one hex nibble
;On Entry:
;  Nibble in low 4 of a
;Trashes psw,b
;----------------------------------------
PHXNIB:	ani	0Fh		;get low nibble
	cpi	0Ah		;A-F?
	jc	PHXN1
	adi	'A'-'9'-1
PHXN1:	adi	'0'		;make it ASCII

	jmp	CONOUT		;trashes b

;***Exit********************************************
;Clear screen and return to PTDOS
;(PTDOS blocks VT character.)
;This routine must be above Solos's User Area USARE
;***************************************************

RSRTRN: mvi	c,16		;clear screen

CSLOOP:	mvi	a,LF
	call	CONOUT
	dcr	c
	jnz	CSLOOP

;Fall into REXIT	

;***Exit**************
;Reset-return to PTDOS
;*********************
REXIT:	call	SYS		;Reset-Return to PTDOS
	db	RESOP		;(page 7-16)

;==========================
;Fake Solos Jump Table
;Must be on a page boundary
;==========================
;----------------------------------
;Create an assembler error if the
;previous segment overlaps this one
;----------------------------------
S2END	equ	$

 if (JMPTBL-S2END)/256
ERROR: SEGMENT OVERLAP
 endif

	org	JMPTBL		;must be page-aligned

;===============================================================
;= This is a fake of Solos's and Cuter's jump table. In most   =
;= cases, the jumps are directly to the equivalent Solos/Cuter =
;= routine. The exception is the "return" jump, which instead  =
;= clears the screen and then invokes PTDOS's soft reset via a =
;= SYS RESOP call.                                             =
;===============================================================

FSTABL:				;Fake Solos Table

FSOLID:	db	0		;0 for CUTER, 7Fh for SOLOS
	jmp	INIT		;cold-start (goes to SOLOS)
	jmp	RSRTRN		;return (goes to PTDOS)
	jmp	FOPEN		;Use Solos tape routines
	jmp	FCLOS
	jmp	RDBYT
	jmp	WRBYT
	jmp	RDBLK
	jmp	WRBLK
	jmp	SOUT		;Use SOLOS I/O too
	jmp	AOUT
	jmp	SINP
	jmp	AINP

	END








