;LBMEMORY/ASM - MEMORY Command
	TITLE	<MEMORY - LS-DOS 6.2>
;
*GET	SVCMAC:3		;SVC Macro equivalents
*GET	VALUES:3		;Misc. equates
;
PAR_ERR	EQU	44		;Parameter Error
LOWEST	EQU	2600H
;
	ORG	2400H
;
MEMORY	@@CKBRKC		;Break key down?
	JR	Z,BEGINA	;Ok if not
	LD	HL,-1		;  else abort
	RET
;
BEGINA	LD	(EXIT+1),SP	;Save SP Address
;
;	Process any Parameters entered
;
	LD	DE,PRMTBL$	;DE => Parameter Table
	PUSH	DE		;Save Parm table start
	@@PARAM			;Process parameters
	POP	HL		;HL => Parm table start
PERR	JP	NZ,PRMERR	;NZ - Parameter Error
;
;	Legal input - were the entries acceptable ?
;
GDPARMS	CALL	CKPARM		;Valid entries ?
	JR	NZ,PERR		;No - Parameter error
;
	@@FLAGS			;IY => System Flags
;
;	Was the CLEAR (C) parameter entered ?
;
CPARM	LD	BC,0FF00H	;C = Clear byte
	LD	A,(CRESP)	;P/u response
	OR	A		;Any response ?
	JR	Z,NEXTPRM	;No - get next parm
	BIT	0,(IY+CFLAG$)	;If memory frozen,
	JP	NZ,NOMEM	;  can't do it
;
;	CLEAR (C) parm entered - is this a flag ?
;
	BIT	6,A		;Is this a flag ?
	JR	Z,ISNUMER	;No - check if numeric
;
;	Response is a FLAG - Is it NO, OFF, or N ?
;
	INC	B		;Yes or No ?
	JR	NZ,NEXTPRM	;No - get next parm
	JR	FILLMEM		;Yes - Fill mem with 0's
;
;	Response is not a FLAG, check if numeric
;
ISNUMER	LD	HL,FILLBYT+1	;HL => Byte to Fill
	BIT	7,A		;Numeric response ?
	LD	(HL),C		;Stuff byte in LD (HL),nn
	JR	NZ,FILLMEM	;Fill mem with char
;
;	Response must be a string - Is length = 1 ?
;
	AND	00001111B	;P/u length
	DEC	A		;Better be one
	JR	NZ,PERR		;Not - parameter error
;
;	Pick up character at address & stuff away
;
	LD	A,(BC)		;P/u character to fill
	LD	(HL),A		;Stuff in LD (HL),nn
;
;	Set HL => HIGH$ (if DOS) or LOW$ (@CMNDR)
;
FILLMEM	CALL	GETHILO		;HIGH$ (HL), LOW$ (DE)
	BIT	1,(IY+CFLAG$)	;Executing @CMNDR ?
	JR	Z,USEHIGH	;No - use HIGH$
	EX	DE,HL		;@CMNDR - use LOW$
USEHIGH	LD	DE,MEMORY+200H	;Start clearing here
;
;	Calculate amount of memory to fill
;
	XOR	A		;Clear carry
	SBC	HL,DE		;Get # to fill
	LD	B,H		;Xfer to BC
	LD	C,L
;
;	Fill user area - HIGH$/LOW$ with spec'd byte
;
	LD	H,D		;HL => LOW$
	LD	L,E
	INC	DE		;DE => LOW$ + 1
FILLBYT	LD	(HL),$-$	;Stuff in fill byte
	LDIR			;Fill memory
GOODEX	LD	HL,0		;Good Exit
	RET
;
;	Was the ADDR (A) parameter specified ?
;
NEXTPRM	LD	A,(ARESP)	;P/u Address response
	OR	A		;Specified ?
	JP	Z,HICHECK	;No - get next parm
;
;	 Check for NUMERIC entry
;
	BIT	7,A		;Check NUM bit
	JR	NZ,APARM	;  go if set
;
;	Response must be a string - Is length = 1 ?
;
	AND	00001111B	;P/u length
	DEC	A		;Better be one
	JR	NZ,PERR		;Not - parameter error
;
;	P/u character representation of 'FLAG'
;
	LD	HL,(APARM+1)	;P/u pointer to char
	LD	A,(HL)		;P/u char
	RES	5,A		;  and make UC
	SUB	41H		;Normalize for flag#
	CP	26		;Check on range
	JP	NC,RANGER	;Error if too high
	PUSH	IY
	POP	HL		;P/u base of flags
	LD	D,0
	LD	E,A		;Put offset in DE
	ADD	HL,DE		;Add them together
	LD	(APARM+1),HL	;Set value in response word
;
;	P/u addr, cvrt to Hex ASCII & put in string
;
APARM	LD	DE,$-$		;P/u the address
	LD	HL,HEXADD	;HL => Destination
	@@HEX16			;Cvrt DE to ASCII @ HL
;
;	Convert DE to Decimal ASCII & put in string
;
	EX	DE,HL		;Set HL = Address
	PUSH	HL		;Save addr ptr
	LD	DE,DECADD	;DE => Destination
	@@HEXDEC		;Cvrt HL to ASCII @ DE
	POP	HL		;HL = Address
;
;	P/u word & byte at that address
;
	PUSH	HL		;Save address ptr
	LD	C,(HL)		;P/u byte
	LD	D,C		;P/u the word value
	INC	HL		;  & stuff into the
	LD	E,(HL)		;  message in hex
;
;	Convert Byte to Hex ASCII & stuff in string
;
	LD	HL,OLDBYTE	;HL => Destination
	@@HEX8			;Convert C to ASCII @ HL
;
;	Convert Word to Hex ASCII & stuff in string
;
	LD	HL,OLDWORD	;HL => Destination
	@@HEX16			;Cvt DE to ASCII @ HL
	POP	IX		;Recover Address ptr
;
;	Was WORD or BYTE parameter entered ?
;
	LD	HL,BRESP	;HL => Byte Response
	LD	DE,WRESP	;DE => Word Response
	LD	A,(DE)		;Anything entered ?
	OR	(HL)
	JR	NZ,WHICH	;Yes - which one
;
;	Neither Entered - Modify string
;
	LD	HL,OLDWORD+5	;End string
	LD	(HL),')'	;Don't display new word
	INC	HL
	LD	(HL),' '
	INC	HL
	LD	(HL),' '
	INC	HL
	LD	(HL),ETX
	JR	DSPSTR		;Display string
;
;	One or Both was entered - ensure both not
;
WHICH	LD	A,(DE)		;Word entered ?
	OR	A
	JR	Z,BPARM		;No - get byte
;
;	Word Entered - Make sure byte wasn't entered
;
	LD	A,(HL)		;Entered ?
	OR	A
	JP	NZ,PRMERR	;Yes - parameter error
;
;	Pick up Word Value & Stuff into Memory
;
WPARM	LD	DE,$-$		;P/u word
	LD	(IX),D		;Stuff lsb
	LD	(IX+1),E	;Stuff msb
;
;	Cvt Word/Byte to Hex ASCII & put in string
;
STUFVAL	LD	HL,NEWWORD	;HL => Destination
	@@HEX16			;Cvrt DE to hex in (HL)
	JR	DSPSTR		;Display String
;
;	Stuff byte into mem if between 0-255
;
BPARM	LD	DE,00FFH	;P/u byte
	LD	A,D		;Hi-order must = 0
	OR	A
	JP	NZ,PRMERR	;No - Parm error
	LD	(IX),E		;Stuff LSB into string
;
;	Convert byte to Hex ASCII & stuff in string
;
	LD	C,E		;Set C = new byte
	LD	HL,NEWBYTE	;HL => New byte
	@@HEX8			;Cvt C to ASCII @ HL
;
;	Display address string
;
DSPSTR	LD	HL,ADDMSG	;HL => Message
	CALL	DSPLY		;Display it
;
;	Display Word/Byte string
;
	LD	HL,OLDWORD	;HL => "Word string"
	LD	A,(BRESP)	;Byte response
	OR	A		;Specified
	JR	Z,DSPSTR2	;No - display Word string
	LD	HL,OLDBYTE	;Yes - use Byte string
DSPSTR2	CALL	DSPLY		;Display string
;
;	HIGH$ & LOW$ check - Was HIGH$ entered ?
;
HICHECK	CALL	GETHILO		;HIGH$ (HL), LOW$ (DE)
	LD	(OLDHI),HL	;Put old HIGH$ in header
	LD	A,(HRESP)	;HIGH$ = value ?
	OR	A
	JR	Z,LOCHECK	;No - check LOW$
	BIT	0,(IY+CFLAG$)	;If memory frozen,
	JP	NZ,NOMEM	;  can't do it
;
;	HIGH$ entered, p/u value & check range
;
HPARM	LD	BC,$-$		;P/u requested new HIGH$
	SBC	HL,BC		;New HIGH$ > old HIGH$ ?
	JP	C,RANGER	;Yes - Range error
;
;	Create Header String & establish true HIGH$
;
	PUSH	DE		;Save DE
	LD	D,B		;Set DE = HIGH$ + 1
	LD	E,C
	INC	DE
	LD	HL,HD_ADD	;Convert DE to Hex ASCII
	@@HEX16			;  at HL (BC is preserved)
	LD	HL,-HLEN	;Set HL = actual HIGH$
	ADD	HL,BC		;  including header size
	POP	DE		;Restore LOW$
;
;	Was LOW$ entered ?
;
LOCHECK	LD	A,(LRESP)	;P/u response
	OR	A		;Entered ?
	JR	Z,CHKBOTH	;No - check range
	BIT	0,(IY+CFLAG$)	;If memory frozen,
	JP	NZ,NOMEM	;  can't do it
;
;	LOW$ entered - cannot be below LOWEST
;
LPARM	LD	DE,$-$		;P/u value entered
	LD	BC,LOWEST	;BC = lowest possible
	EX	DE,HL		;  memory location
	PUSH	HL
	SBC	HL,BC		;In range ?
	POP	HL
	EX	DE,HL
	JP	C,RANGER	;No - display range error
;
;	HL = HIGH$, DE = LOW$ - do they overlap ?
;
CHKBOTH	PUSH	HL		;HIGH$ must be
	OR	A		;  greater than or equal
	SBC	HL,DE		;  to LOW$.
	POP	HL
	JP	C,RANGER	;Less - range error
;
;	LOW$ and HIGH$ are both valid - set LOW$
;
	EX	DE,HL		;Pt DE => HI$, HL => LOW$
	LD	B,1
	@@HIGH$			;Set LOW$
;
;	Was the HIGH parameter specified ?
;
	LD	A,(HRESP)	;Was HIGH specified ?
	OR	A
	JR	Z,DSPHI		;No - don't alter it
;
;	Yes - Change Exit message to include header
;
	LD	A,LF		;Change C/R to a L/F
	LD	(HEADMES),A
;
;	Xfer header into high memory
;
	PUSH	DE		;Save HIGH$ ptr
	INC	DE		;Pt to header destination
	LD	HL,HEADER	;HL => Header
	LD	BC,HLEN		;BC = header length
	LDIR			;Xfer to mem
	POP	HL		;HL => HIGH$ (BC = 0)
	@@HIGH$			;Set HIGH$ (func. 0)
;
;	P/u HIGH$/LOW$, cvt to Hex, & put in string
;
DSPHI	CALL	GETHILO		;HIGH$ (HL), LOW$ (DE)
	PUSH	HL		;Save HIGH$ ptr
	LD	HL,LOWIS1	;HL => Destination
	@@HEX16			;Cvt DE to ASCII @ HL
	POP	DE		;DE = HIGH$
	LD	HL,HIGHIS1	;HL => Destination
	@@HEX16			;Cvt DE to ASCII @ HL
;
;	Display HIGH$ = nnnn & LOW$ = nnnn string
;
	LD	HL,HIGHIS	;HL => HIGH$/LOW$ string
	@@LOGOT			;Log & display
	LD	HL,HEADMES	;Display Header message
	@@LOGOT			;  if one was inserted
;
;	Was a Go Parameter Entered ?
;
GO	LD	A,(GRESP)	;GO entered ?
	OR	A
	JP	Z,GOODEX	;No - RETurn HL = 0
GPARM	JP	$-$		;Yes - Jump to address
;
;	GETHILO - Get HIGH$ in HL, & LOW$ in DE
;
GETHILO	LD	HL,0		;P/u LOW$
	LD	D,H		;Set DE = 0
	LD	E,L
	LD	B,1
	@@HIGH$
	EX	DE,HL		;Save in DE
	LD	B,L		;Set B = 0
	@@HIGH$			;Get HIGH$ & RETurn
	RET			;RETurn
;
;	DSPLY - Display a line to the video
;
DSPLY	@@DSPLY			;Display line
	RET	Z		;Z - RETurn
	DB	21H		;Skip LD A,## instruction
;
;	IOERR - Fatal Error Handler
;
PRMERR	LD	A,PAR_ERR	;Parameter Error
IOERR	LD	L,A		;Error # to HL
	LD	H,0
	OR	0C0H		;Short error message
	LD	C,A		;Save in C
	@@ERROR			;Display error
	JR	EXIT		;Go to exit routine
;
;	CKPARM - Check if Parameter types are legal
;	HL => Beginning of Parameter Table
;	Z  <= Set if Parameters entered were legal
;
GOODPRM	POP	DE		;Clear stack
CKPARM	INC	HL		;Bump past 80H
	LD	A,(HL)		;P/u type byte
	LD	B,A		;Save in B
	AND	0FH		;Get length
	RET	Z		;Zero - finished
;
;	Position HL to response byte
;
	INC	HL		;HL => Parameter Name
	PUSH	HL		;Save start of name
	LD	E,A		;Set DE = name
	LD	D,0		;  length.
	ADD	HL,DE
;
;	Pick up response, mask off junk, & xfer in D
;
	LD	A,(HL)		;P/u response
	AND	0E0H		;Bits 7-5 = response
	LD	D,A		;Save in D
;
;	Was the response bit acceptable by type ?
;
	LD	A,B		;P/u type byte
	AND	D		;Mask off bits 4-0
	XOR	D		;Result = Z if both set
;
;	Position HL to next parameter entry
;
	INC	HL		;Go past word
	INC	HL
	JR	Z,GOODPRM	;Z - good entry
;
;	Illegal Entry - Recover Name start & RETurn
;
	LD	C,E		;Set BC = length
	LD	B,0
	POP	HL		;HL => Parameter Name
	RET			;RETurn NZ
;
;	6.2 Memory Header
;
HEADER	JR	MEMSTRT		;JR to start of module
OLDHI	DW	0		;HIGH$ before this module
	DB	5,'&'		;Use "&" to denote addr.
HD_ADD	DB	'nnnn'		;Hex ASCII address
MEMSTRT	EQU	$		;Length byte
HLEN	EQU	$-HEADER	;Length of Header
;
;
;	Messages
;
;
NOMEM	LD	HL,NOMEM$
	DB	0DDH
RANGER	LD	HL,RANGER$
;
;	Display & Log message, & RETurn
;
	@@LOGOT			;Display/Log message
ABORT	LD	HL,-1		;Internal Error
EXIT	LD	SP,$-$		;P/u old SP address
	@@CKBRKC		;Clear any Break
	RET			;RETurn
;
NOMEM$	DB	'No memory space available',CR
RANGER$	DB	'Range error',CR
;
;	PARAMETER TABLE
;
PRMTBL$	DB	80H		;6.x type @PARAM
;
;	HIGH (H) - Accept Numeric input only
;
	DB	NUM!ABB!4
	DB	'HIGH'
HRESP	DB	0
	DW	HPARM+1
;
;	LOW (L) - Accept numeric input only
;
	DB	NUM!ABB!3
	DB	'LOW'
LRESP	DB	0
	DW	LPARM+1
;
;	ADD (A) - Accept numeric, string input
;
	DB	NUM!STR!ABB!3
	DB	'ADD'
ARESP	DB	0
	DW	APARM+1
;
;	WORD (W) - Accept Numeric input only
;
	DB	NUM!ABB!4
	DB	'WORD'
WRESP	DB	0
	DW	WPARM+1
;
;	BYTE (B) - Accept Numeric input only
;
	DB	NUM!ABB!4
	DB	'BYTE'
BRESP	DB	0
	DW	BPARM+1
;
;	GO (G) - Accept Numeric input only
;
	DB	NUM!ABB!2
	DB	'GO'
GRESP	DB	0
	DW	GPARM+1
;
;	CLEAR (C) - Accept Flag, Numeric or string input
;
	DB	FLAG!NUM!STR!ABB!5
	DB	'CLEAR'
CRESP	DB	0
	DW	CPARM+1
;
	NOP
;
HIGHIS	DB	'High = X',AP
HIGHIS1	DB	'xxxx',AP,'  Low = X',AP
LOWIS1	DB	'xxxx',AP,ETX
;
ADDMSG	DB	'X',AP
HEXADD	DB	'nnnn',AP,' = '
DECADD	DB	'ddddd (X',AP,ETX
;
OLDWORD	DB	'nnnn',AP,' => X',AP
NEWWORD	DB	'nnnn',AP,')  ',ETX
;
OLDBYTE	DB	'nn',AP,' => X',AP
NEWBYTE	DB	'nn',AP,')  ',ETX
;
HEADMES	DB	CR,'Note : Memory Header Inserted',CR
;
	END	MEMORY
