Explore an 8080 with Educator-8080 - Program Listing

The Educator-8080 program expressed as an absolute assembly language listing. The notations <0>, <1>, <2> and <3> are used to denote the high order (page) address bytes of four consecutive pages in memory address space. When loading the program into a given system, these notations become bytes with consecutive octal values. Thus to load the program at location 200/000 in memory address space, the values utilized would be 200, 201, 202 and 203.


  address      octal-code         label    op      operand                      commentary


*The control routine is the top of the structure and controls the operation of the entire program.

<0>/000         061 xxx xxx     CNTRL   LXI     SP,STACK        Set stack pointer to programmable memory;
<0>/003 	315 026 <0> 	NOTZER  CALL	DSPLY           Display contents of registers;
<0>/006 	315 316 <0> 	  	CALL	CMDNT           Enter a command;
<0>/011 	315 063 <1> 	  	CALL	FETCH           Fetch the correct opcode;
<0>/014 	267 	  	        ORA	A               Set zero flag as per contents;
<0>/015 	302 003 <0> 	  	JNZ	NOTZER 		Jump if not zero error occurred;
<0>/020 	315 030 <2> 	  	CALL	XQTER 		Go execute the current command;
<0>/023 	303 003 <0> 	  	JMP	NOTZER	 	Loop forever;
 
*This display routine controls the generation of the dynamic display.

<0>/026 	041 167 <3> 	DSPLY 	LXI	H,TITLS 	Load address of titles into HL;
<0>/031 	315 261 <0> 	  	CALL	CHEDT 		Display titles;
<0>/034 	041 257 <3> 	  	LXI	H,BLINE 	Load addr of BLINE title;
<0>/037 	072 351 <3> 	  	LDA	BREG 		Load contents of BREG into A;
<0>/042 	315 132 <0> 	  	CALL	DSPCV 		Convert and display;
<0>/045 	041 271 <3> 	  	LXI	H,CLINE 	Load addr of CLINE title;
<0>/050 	072 350 <3> 	  	LDA	CREG 		Load contents of CREG into A;
<0>/053 	315 132 <0> 	  	CALL	DSPCV 		Convert and display;
<0>/056 	041 004 <0> 	  	LXI	A,AFHDR 	Load addr of A flags title;
<0>/061 	315 261 <0> 	  	CALL	CHEDT 		Display titles;
<0>/064 	052 346 <3> 	  	LHLD	PSWA 		Load flags and A into HL;
<0>/067 	175 	  		MOV	A,L 		Move flags to A;
<0>/070		346 004 	  	ANI	B'00000100' 	AND off all but parity flag;
<0>/072		315 237 <0> 	  	CALL	DSPFG 		Display the flag value;
<0>/075 	175 	  		MOV	A,L 		Move flags to A;
<0>/076 	346 100 	  	ANI	B'01000000' 	AND off all but zero flag;
<0>/100 	315 237 <0> 	  	CALL	DSPFG 		Display the flag value;
<0>/103 	175 	  		MOV	A,L 		Move flags to A;
<0>/104 	346 200 	  	ANI	B'10000000' 	AND off all but sign flag;
<0>/106 	315 237 <0> 	  	CALL	DSPFG 		Display the flag value;
<0>/111 	175 	  		MOV	A,L 		Move flags to A;
<0>/112 	346 020 	  	ANI	B'00010000' 	AND off all but auxiliary carry flag;
<0>/114 	315 237 <0> 	  	CALL	DSPFG 		Display the flag value;
<0>/117 	175 	  		MOV	A,L 		Move flags to A;
<0>/120 	346 001 	  	ANI	B'00000001' 	AND off all but carry flag;
<0>/122 	315 237 <0> 	  	CALL	DSPFG 		Display the flag value;
<0>/125 	174 	  		MOV	A,H 		Move A register value to A;
<0>/126 	315 137 <0> 	  	CALL	DSPCN 		Display with no title print;
<0>/131 	311 	  		RET	  		Return to the CNTRL routine;
 
*The display conversion routine prints binary, octal fnd hexadecimal.

<0>/132		365		DSPCV	PUSH	PSW		Save output value for CHEDT;
<0>/133		315 261	<0>		CALL	CHEDT		Display line title addr in HL;
<0>/136		361			POP	PSW		Retrieve saved output value;
<0>/137		036 010		DSPCN	MVI	E,Q#010'	Move 8 to E register;
<0>/141		007		DSPBT	RLC			Rotate MSB into Carry and LSB;
<0>/142		365			PUSH	PSW		Save current value;
<0>/143		346 001			ANI	Q'001'		AND off all but LSB;
<0>/145		315 237 <0>		CALL	DSPFG		Go display bit value;
<0>/150		361			POP	PSW		Retrieve saved current value;
<0>/151		035			DCR	E		Decrement loop count;
<0>/152		302 141 <0>		JNZ	DSPBT		Jump if loop count not zero;
<0>/155		267			ORA	A		Reset carry;
<0>/156		036 003			MVI	E,Q'003'	Move 3 to E register;
<0>/160		027		DSPQT	RAL			MSB to Carry. Carry to LSB.
<0>/161		027			RAL			do it again, t
<0>/162		027			RAL			three times for octal digit shift;
<0>/163		365			PUSH	PSW	Save current value;
<0>/164		346 007			ANI	Q'007'		AND off all but octal LSD;
<0>/166		366 060			ORI	Q'060'		OR on bits to make ASCII numeric character;
<0>/170		315 xxx xxx		CALL	CHRPR		Output the character;
<0>/173		361			POP	PSW		Retrieve saved current value;
<0>/174		035			OCR	E		Decrement loop count;
<0>/175		302 160 <0>		JNZ	DSPQT		Jump if loop count not zero;
<0>/200		315 251 <0>		CALL	DSPSP		Output a space;
<0>/203		036 002			MVI	E,Q'002'	Move 2 to E ;
<0>/205		007		DSPHT	RLC			Rotate MSB into Carry and LSB,
<0>/206		007			RLC			do it again.
<0>/207		007			RLC			four times for.
<0>/210		007			RLC			hexadecimal shift;
<0>/211		365			PUSH	PSW		Save current value;
<0>/212		346 017			ANI	B'00001111'	AND off all but hexadecimal LSD;
<0>/214		306 060			ADI	Q'060'		Add on bits to make ASCII numeric character
<0>/216		376 072			CPI	Q'072'		Compare result to one more than 9;
<0>/220		332 225 <0>		JC	DSPHS		If numeric then skip adjustment;
<0>/223		306 007			ADI	Q'007'		Add 7 giving ASCII 'A' thru 'F' codes;
Listing 1, continued:


    address      octal-code         label    op      operand                      commentary


→ <0>/225	315 xxx xxx	DSPHS	CALL	CHRPR		Output the character;
  <0>/230	361			POP	PSW		Retrieve saved current value;
  <0>/231	000			NOP
  <0>/232	035			DCR	E		Decrement loop count;
  <0>/233	302 205 <0>		JNZ	DSPHT		Jump if loop count not zero;
  <0>/236	311			RET			Return to calling routine;

  *Display flag or binary digit followed by a space. Alternate entry is used to display a space.

  <0>/237	312 244 <0>	DSPFG	JZ	DSPFZ		Jump if passed value is a zero;
  <0>/242	076 001			MVI	A,Q'001'	Otherwise move a 1 into A;
  <0>/244	306 060		DSPFZ	ADI	Q'060'		Convert into ASCII numeric character;
→ <0>/246	315 xxx xxx		CALL	CHRPR		Output the character;
  <0>/251	365		DSPSP	PUSH	PSW		Save the flags and value in A;
  <0>/252	076 040			MVI	A,Q'040'	Move space into A;
→ <0>/254	315 xxx xxx		CALL	CHRPR		Output the space;
  <0>/257	361			POP	PSW		Retrieve the saved flags and A;
  <0>/260	311			RET			Return to the calling routine;

  *The character string output edit routine.

  <0>/261	176		CHEDT	MOV	A,M		Move next character into A;
  <0>/262	376 200			CPI	Q'200'		Compare it to 200 octal;
  <0>/264	310			RZ			Return if equal it's end of string;
  <0>/265	322 277 <0>		JNC	CHSPA		Jump if greater for space routine;
→ <0>/270	315 xxx xxx		CALL	CHRPR		Else go output the character;
  <0>/273	043		CHEND	INX	H		Increment the string index;
  <0>/274	303 261 <0>		JMP	CHEDT		Loop for next character;
  <0>/277	326 200		CHSPA	SUI	Q'200'		Subtract 200 octal from value;
  <0>/301	107			MOV	B,A		Move space count to B;
  <0>/302	076 040		CHSPL	MVI	A,Q'040'	Move space to A;
→ <0>/304	315 xxx xxx		CALL	CHRPR		Output the space;
  <0>/307	005			DCR	B		Decrement space count;
  <0>/310	302 302 <0>		JNZ	CHSPL		Jump if count not zero to start of loop;
  <0>/313	303 273 <0>		JMP	CHEND		Jump back into CHEDT loop;

  *The command entry routine accepts input from the keyboard for commands.

  <0>/316	041 332 <3>	CMDNT	LXI	H,CMDMS		Move address of 'COMMAND?' to HL;
  <0>/321	315 261 <0>		CALL	CHEDT		Display the message;
  <0>/324	041 352 <3>		LXI	H,CMDAR		Move address of command input area HL;
  <0>/327	006 026			MVI	B,Q'026'	Move maximum length to B;
→ <0>/331	315 xxx xxx	CMDKB	CALL	KEYBD		Get an input character;
  <0>/334	376 014			CPI	Q'014'		Is it a control-1 line delete?
  <0>/336	312 000 <0>		JZ	CNTRL		If so then restart program;
  <0>/341	376 015			CPI	Q'015'		Is it a carriage return?
  <0>/343	312 376 <0>		JZ	CMDND		If so then go compress input;
  <0>/346	376 177			CPI	Q'177'		Is it a delete character?
  <0>/350	302 355 <0>		JNZ	CMDST		If not then go store the character;
  <0>/353	076 033			MVI	A,Q'033'	If so replace with back arrow;
  <0>/355	167		CMDST	MOV	M,A		Store input character in command buffer;
→ <0>/356	315 xxx xxx		CALL	CHRPR		Display the input character;
  <0>/361	043			INX	H		Increment command work area index;
  <0>/362	005			DCR	B		Decrement command length count;
  <0>/363	302 331 <0>		JNZ	CMDKB		If not full then reiterate;
  <0>/366	076 001			MVI	A,Q'001'	If buffer full then select error
  <0>/370	315 063 <2>		CALL	ERROR		number 1 and print its message;
  <0>/373	303 000 <0>		JMP	CNTRL		Restart the program;

  *The command compress routine eliminates all but letters and numbers.

  <0>/376	041 352 <3>	CMDND	LXI	H,CMDAR		Load HL with address of work area;
  <1>/001	345			PUSH	H		Push & pop move it to DE
  <1>/002	321			POP	D		as the compression pointer;
  <1>/003	076 026			MVI	A,Q'026'	Load A with maximum length;
  <1>/005	220			SUB	B		Subtract remaining length from B;
  <1>/006	107			MOV	B.A		Move actual length to B;
  <1>7007	176		CMDNX	MOV	A,M		Move command character to A;
  <1>/010	376 033			CPI	Q'033'			Is it a back arrow (character delete)?
  <1>/012	302 027 <1>		JNZ	CMDCH		If not then go to other tests;
  <1>/015	076 352			MVI	A,CMDAR-L	Low address byte of CMDAR to A;
  <1>/017	273			CMP	E		Compare to current low address byte;
  <1>/020	322 055 <1>		JNC	CMDNS		If not greater then skip save;
  <1>/023	033			DCX	D		Else back up compression pointer;
  <1>/024	303 055 <1>		JMP	CMDNS		Skip saving the character;
  <1>/027	376 060		CMDCH	CPI	Q'060'		Is the character less than 'O'?
  <1>/031	332 055 <1>		JC	CMDNS		If so then skip saving it;
  <1>/034	376 072			CPI	Q'072'		Is the character less than '9' + 1?
  <1>/036	332 053 <1>		JC	CMDSV		If so then save numeric value;
  <1>/041	376 101			CPI	Q'101'		Is the character leu than 'A'?
  <1>/043	332 055 <1>		JC	CMDNS		If so then skip saving it;
  <1>/046	376 133			CPI	Q'133'		Is the character greater than 'Z'?
  <1>/050	322 055 <1>		JNC	CMDNS		If so then skip saving it;
  <1>/053	022 		CMDSV	STAX	D		Store character in compressed area;
  <1>/054	023 			INX	D		Increment compression pointer index;
  <1>/055	043		CMDNS	INX	H		Increment input string pointer;
  <1>/056	005			DCR	B		Decrement actual length count;
  <1>/057	302 007 <1>		JNZ	CMDNX		If length is not zero then reiterate;
  <1>/062	311			RET			Else return to CNTRL calling point;

*The FETCH instruction/command routine validates and builds the object code.

  <1>/063	041 122 <2>	FETCH	LXI	H,OPTAB		Load address of opcode table HL;
  <1>/066	036 037			MVI	E,Q'037'	Move table element count to E;
  <1>/070	345		FLOOP	PUSH	H		Save current element address;
  <1>/071	001 352 <3>		LXI	B,CMDAR		Load address of CMDAR into BC;
  <1>/074	026 003			MVI	D,Q'003'	Move opcode length to D;
  <1>/076	012		FCOMP	LDAX	B		Load command character to A indexed by B;
  <1>/077	276			CMP	M		Compare it to table character;
  <1>/100	302 125 <1>		JNZ	FNXEL		lf not equal then go to next element;
  <1>/103	003			INX	B		Increment command character index;
  <1>/104	043			INX	H		Increment table character index;
  <1>/105	025			DCR	D		Decrement opcode length counter;
  <1>/106	302 076 <1>		JNZ	FCOMP		If not zero continue test loop;
  <1>/111	343			XTHL			Exchange HL with top of stack;
  <1>/112	341			POP	H		Pop HL from stack to clear it;
  <1>/113	136			MOV	E,M		Move naked opcode to E, D is zero;
  <1>/114	325			PUSH	D		Save naked opcode;
  <1>/115	043			INX	H		Increment table pointer;
  <1>/116	136			MOV	E,M		Decode routine low address byte to E;
  <1>/l17	043			INX	H		Increment table pointer;
  <1>/120	126			MOV	D,M		Decode routine high address byte to D;
  <1>/121	353			XCHG			Move decode routine address to HL;
Listing 1, continued:


  address      octal-code         label    op      operand                      commentary


<1>/122		321			POP	D		Unsave naked opcode to DE;
<1>/123		257			XRA	A		Clear A, no error code;
<1>/124		351			PCHL			Jump to address of decode routine;
<1>/125		001 006	000	FNXEL	LXI	B,Q'000006'	Load double length 6 into BC;
<1>/130		341			POP	H		Unsave current element address;
<1>/131		011			DAD	B		Add 6 to it;
<1>/132		035			DCR	E		Decrement table element count;
<1>/133		302 070	<1>		JNZ	F LOOP		Reiterate to test next element;
<1>/136		076 002			MVI	A,Q'002'	Move error code 2 to A;
<1>/140		303 063	<2>		JMP	ERROR		Go display error 2, opcode unknown;
<1>/143		000			NOP			No operation filler;

*The instruction decoder routines follow.

*Instructions using the DIRCT routine require no decoding. Example RAL, CMA, etc.

<1>/144		311		DIRCT	RET			Return to CNTRL for execution;

* The MOVRT is used only by the MOV command.

<1>/145		315 245 <1>	MOVRT	CALL	RG543		Validate destination register;
<1>/150		267			ORA	A		Set flags based on A contents;
<1>/151		300			RNZ			Return not zero with error;
								Else fall thru to RG210;

*Instructions using the RG210 routine require a source register.

<1>/152		012		RG210	LDAX	B		Load next command character into A;
<1>/153		003			INX	B		Increment command character index;
<1>/154		315 173 <1>		CALL	REGAN		Analyze for valid register;
<1>/157		322 166 <1>		JNC	RGERR		If CY=0 then register not valid;
<1>/162		203			ADD	E		Add naked opcode to register value;
<1>/163		137			MOV	E,A		Move result back to E;
<1>/164		257			XRA	A		Clear A indicating no errors;
<1>/165		311			RET			Return to CNTRL;

*The register error routine is used to indicate register designation errors.

<1>/166		076 003		RGERR	MVI	A,Q'003'	Move error code 3 to A;
<1>/170		303 063 <2>		JMP	ERROR		Go display error 3, invalid register;

*The register analysis and validation routine is used by RG543, RG210 and RG54B.

<1>/173		326 101		REGAN	SUI	Q'101'		Subtract an 'A' from the character;
<1>/175		376 003			CPI	Q'003'		Compare the result to 3;
<1>/177		320			RNC			If not less than 3 return with CY=0;
<1>/200		075			DCR	A		Decrement result: A=377, B=000, C=001;
<1>/201		346 007			ANI	Q'007'		AND off all but octal LSD;
<1>/203		067			STC			Set CY=1 indicating no error;
<1>/204		311			RET			Return to calling routine;

*The MVIRT is used only by the MVI command.

<1>/205		315 245 <1>	MVIRT	CALL	RG543		Validate destination register;
<1>/210		267			ORA	A		Set flags based on A contents;
<1>/211		300			RNZ			Return not zero with error;
								Else fall thru to IMMED;

*Instructions requiring an immediate operand use the IMMED routine.

<1>/212		012		IMMED	LDAX	B		Load next command character into A;
<1>/213		003			INX	B		Increment command character index;
<1>/214		376 102			CPI	Q'102'		Is the command character a 'B'?
<1>/216		312 301 <1>		JZ	BINRY		If so then process as binary;
<1>/221		376 121			CPI	Q'121'		Is the command character a 'Q'?
<1>1222		312 336 <1>		JZ	OCTAL		If so then process as octal;
<1>/226		376 110			CPI	Q'110'		Is the command character an 'H'?
<1>/230		312 367	<1>		JZ	HEX		If so then process as hexadecimal;
<1>/233		376 070			CPI	Q'070'		Is the command character less than '8'?
<1>/235		332 335 <1>		JC	OCTAD		If so then treat as octal;
<1>/240		076 005			MVI	A,Q'005'	Move error code 5 to A;
<1>/242		303 063 <2>		JMP	ERROR		Go display error 5, invalid immediate;

*Instructions using the RG543 routine require a destination register.

<1>/245		012		RG543	LDAX	B		Load next command character into A;
<1>/246		003			INX	B		Increment command character index;
<1>/247		315 173 <1>		CALL	REGAN		Analyze for valid register;
<1>/252		322 166 <1>		JNC	RGERR		If CY=0 then register not valid;
<1>/255		007			RLC			Shift octal register value
<1>7256		007			RLC			  left three
<1>/257		007			RLC			     places;
<1>/260		203			ADD	E		Add naked opcode to shifted value;
<1>/261		137			MOV	E,A		Move result back to E;
<1>/262		257			XRA	A		Clear A indicating no errors;
<1>/263		311			RET			Return to calling routine;

*Instructions using the RG54B routine are INX and DCX.

<1>/264		012		RG54B	LDAX	B		Load next command character into A;
<1>/265		003			INX	B		Increment command character index;
<1>/266		315 173 <1>		CALL	REGAN		Analyze for valid register;
<1>/271		376 000			CPI	Q'000'		Is the register a zero?
<1>/273		310			RZ			If so it's 'B' so return;
<1>/274		076 004			MVI	A,Q'004'	Move error code 4 to A;
<1>/276		303 063 <2>		JMP	ERROR		Go display error 4, invalid register;

*The BINRY routine converts a binary immediate value into usable form.

<1>/301		046 010		BINRY	MVI	H,Q'010'	Move 8 to H for count;
<1>/303		012		BLOOP	LDAX	B		Load next command character into A;
<1>/304		326 060			SUI	Q'060'		Subtract a '0' from it;
<1>/306		376 002			CPI	Q'002'		Is the result less than 2?
<1>/310		322 330 <1>		JNC	IMMER		If not then go display immediate error;
<1>/313		345			PUSH	H		Save the count;
<1>/314		152			MOV	L,D		Move D to L (immediate byte);
<1>/315		051			DAD	H		Shift HL left one bit;
<1>/316		205			ADD	L		Add L to bit in A;
Listing 1, continued:


  address      octal-code         label    op      operand                      commentary


<1>/317		127			MOV	D,A		Move the result back to D;
<1>/320		341			POP	H		Unseve the count;
<1>/321		003			INX	B		Increment command character index;
<1>/322		045			DCR	H		Decrement the count;
<1>/323		302 303 <1>		JNZ	BLOOP		If not zero then reiterate;
<1>/326		257			XRA	A		Clear A indicating no errors;
<1>/327		311			RET			Return to CNTRL;

*The immediate error routine is used to indicate immediate value errors.

<1>/330		076 006		IMMER	MVI	A,Q'006'	Move error code 3 to A;
<1>/332		303 063 <2>		JMP	ERROR		Go display error 3, invalid immediate;

*The OCTAD entry point to the OCTAL routine it for the default condition.

<1>/335		013		OCTAD	DCX	B		Decrement command character index;

*The OCTAL routine converts an octal immediate value into usable form.

<1>/336		046 003		OCTAL	MVI	H,Q'003'	Move a 3 into H for count;
<1>/340		012		OLOOP	LDAX	B		Load next command character into A;
<1>/341		326 060			SUI	Q'060'		Subtract a '0' from it;
<1>/343		376 010			CPI	Q'010'		Is command character less than 8?
<1>/345		322 330 <1>		JNC	IMMER		If not then go display immediate error;
<1>/350		345			PUSH	H		Save the count;
<1>/351		152			MOV	L,D		Move D to L immediate byte;
<1>/352		051			DAD	H		Shift immediate
<1>/353		051			DAD	H		  byte left
<1>/364		051			DAD	H		    three bits;
<1>/355		206			ADD	L		Add L to value in A;
<1>/356		127			MOV	D,A		Move result beck to D;
<1>/357		341			POP	H		Unsave the count;
<1>/360		003			INX	B		Increment command character index;
<1>/361		045			DCR	H		Decrement the count;
<1>/362		302 340 <1>		JNZ	OLOOP		If not zero then reiterate;
<1>/365		257			XRA	A		Clear A indicating no errors;
<1>/366		311			RET			Return to CNTRL;

*The HEX routine converts a hexadecimal immediate value into usable form.

<1>/367		046 002		HEX	MVI	H,Q'002'	Move a 2 into H for count;
<1>/371		012		HLOOP	LDAX	B		Load next command character into A;
<1>/372		326 060			SUI	Q'060'		Subtract a '0' from it;
<1>/374		376 012			CPI	Q'012'		Is it less then '9' + 1?
<1>/376		332 010 <2>		JC	HCHOK		If so then numeric character is OK;
<2>/001		326 007			SUI	Q'007'		Else convert alphabetic to numeric;
<2>/003		376 020			CPI	Q'020'		Is character value greater than 15?
<2>/005		322 330 <1>		JNC	IMMER		If so then invalid hexadecimal value;
<2>/010		345		HCHOK	PUSH	H		Save the count;
<2>/011		152			MOV	L,D		Move D to L immediate byte;
<2>/012		051			DAD	H		Shift immediate
<2>/013		051			DAD	H		  byte left
<2>/014		051			DAD	H		    four
<2>/015		051			DAD	H		      bits;
<2>/016		205			ADD	L		Add L to value in A;
<2>/017		127			MOV	D,A		Move result back to D;
<2>/020		341			POP	H		Unsave the count;
<2>/021		003			INX	B		Increment command character index;
<2>/022		045			DCR	H		Decrement the count;
<2>/023		302 371 <1>		JNZ	HLOOP		If not zero then reiterate;
<2>/026		257			XRA	A		Clear A indicating no errors;
<2>/027		311			RET			Return to CNTRL;

*The XQTER routine executes the generated object code for Educator-8080.

<2>/030		353		XQTER	XCHG			Move generated opcode to HL;
<2>/031		042 046 <2>		SHLD	XQTOP		Store it at execution point;
<2>/034		052 346 <3>		LHLD	PSWA		Load working PSW & A into HL;
<2>/037		345			PUSH	H		Push & pop sets values for
<2>/040		361			POP	PSW		  working register and flags;
<2>/041		052 350 <3>		LHLD	BANDC		Load working B and C into HL;
<2>/044		345			PUSH	H		Push & pop sets values for
<2>/045		301			POP	B		   working B and C registers;
<2>/046		000		XQTOP	NOP			The command to be executed;
<2>/047		000			NOP			Immediate value or NOP;
<2>/050		305			PUSH	B		Push B and C working register values;
<2>/051		341			POP	H		Pop them into HL;
<2>/052		042 350 <3>		SHLD	BANDC		Store them in save area;
<2>/055		365			PUSH	PSW		Push PSW and A working values;
<2>/056		341			POP	H		Pop them into HL;
<2>/057		042 346 <3>		SHLD	PSWA		Store them in save area;
<2>/062		311			RET			Return to CNTRL for next command;I;

* The ERROR routine is used to display error messages.

<2>/063		365		ERROR	PUSH	PSW		Save error code in A;
<2>/064		041 162 <3>		LXI	H,ERRSP		Load address of error header spaces;
<2>/067		315 261 <0>		CALL	CHEDT		Go output error header spaces
<2>/072		361 			POP	PSW		Unsave error code;
<2>/073		041 014 <3>		LXI	H,ERTAB		Load address of error message table;
<2>/076		205			ADD	L		Add low address byte to error code;
<2>/077		157			MOV	L,A		Move result to L, points to offset;
<2>/100		156			MOV	L,M		Move offset to L;

*Note: HL now contains the address of the error message.

<2>/101		315 261 <0>		CALL	CHEDT		Output the error message;
<2>/104		021 000 000	ERTIM	LXI	D,Q'000000'	Load DE with timing loop value;
<2>/107		035			DCR	E		Decrement value in E 256 times;
<2>/110		302 105 <2>		JNZ	ERTIM+1		Reiterate loop 256 times;

*The above JMP goes to the first 000 in the LXI command which is an effective NOP.

<2>/113		025			DCR	D		Decrement D;
<2>/114		302 105 <2>		JNZ	ERTIM+1		Reiterate outer loop 256 times;
<2>/117		076 377			MVI	A,Q'377'	Move a 377 to A indicating error;
<2>/121		311			RET		Return to CNTRL;

*Note: for Teletype or hard copy output bytes <2>/104 thru <2>/116 can be replaced by 000 NOPs.

Programm Listing. [CP/M Quelle]

Eingescanned von Werner Cirsovius
Dezember 2013
© BYTE Publications Inc.