	ORG	000H
	TITLE	'SID HISTOGRAM UTILITY 12/26/77'
;
;	COPYRIGHT (C) 1976,1977
;	DIGITAL RESEARCH
;	BOX 579 PACIFIC GROVE
;	CALIFORNIA 93950
;
;	HISTOGRAM OF PROGRAM EXECUTION FREQUENCY
;	DDT ENTRY POINT
BDOSE	EQU	5	;PRIMARY BDOS ENTRY POINT
DDTBASE	EQU	7*8+1	;RESTART ENTRY POINT HAS BASE
HISTO:	JMP	SETUP	;INITIAL ENTRY FROM RELOCATOR
;
;	SYMBOL TABLE INITIALIZED TO INITIAL, COLLECT, DISPLAY
SYBASE:
	DB	'YALPSID',7,LOW DISE,HIGH DISE	;DISPLAY
	DB	'TCELLOC',7,LOW COLE,HIGH COLE	;COLLECT
	DB	'LAITINI',7,LOW INIE,HIGH INIE	;INITIAL
SYLEN	EQU	$-SYBASE	;LENGTH OF ADDITIONAL SYMBOLS
;
INIE:	JMP	INITIAL
COLE:	JMP	COLLECT
DISE:	JMP	DISPLAY
	DB	'COPYRIGHT (C) 1977 DIGITAL RESEARCH   '
;	DDT SUBROUTINES
GETBUFF:
;	READ NEXT COMMAND BUFFER
	LXI	B,3
	JMP	GODDT
;
GNC:	;READ NEXT CHARACTER TO REGISTER A

	LXI	B,6
	JMP	GODDT
;
PCHAR:	;PRINT CHARACTER FROM REGISTER A

	LXI	B,9
	JMP	GODDT
;
PBYTE:	;PRINT DECODED BYTE FROM REGISTER A

	LXI	B,12
	JMP	GODDT
;
;
PADDR:	;PRINT THE ADDRESS GIVEN BY D,E
	PUSH	D	;SAVE THE ADDRESS FOR THE PRINT
	MOV	A,D	;PRINT HIGH ADDRESS
	CALL	PBYTE
	POP	D	;RECALL
	MOV	A,E	;LOW ADDRESS
	JMP	PBYTE	;RETURN THROUGH PBYTE
;
SCANEXP:
;	SCAN COMMAND LINE FOR 1,2, OR 3 EXPRESSIONS
	LXI	B,18
	JMP	GODDT
;
GETVAL:
;	READ NEXT VALUE FROM SCANEXP CALL TO H,L
	LXI	B,21
;
GODDT:	;PERFORM THE DDT CALL
	LHLD	DDTBASE
	DAD	B
	PCHL
;
;	CONSTANTS
CR	EQU	0DH
LF	EQU	0AH
HSIZE	EQU	64	;SIZE OF HISTOGRAM (MUST CORRESPOND TO SHR6)
;
;	USEFUL SUBROUTINES
DIFF:	;COMPUTE THE DIFFERENCE:  DE = DE - HL
	MOV	A,E
	SUB	L
	MOV	E,A
	MOV	A,D
	SBB	H
	MOV	D,A
	RET
;
SHR6:	;DIVIDE H,L BY 64 (MUST CORRESPOND TO HSIZE)
	MOV	A,L
	MOV	L,H
	MVI	H,0
	DAD	H	;HIGH ORDER * 2
	DAD	H	;HIGH ORDER * 4
	RLC		;MOVE HIGH TWO BITS OF LOW BYTE
	RLC		;TO POSITION IN A
	ANI	11B	;MASK TO REPLACE LOW BITS OF H,L
	ORA	L
	MOV	L,A
	RET
;
CRLF:	;SEND CRLF CHARACTERS
	MVI	A,CR
	CALL	PCHAR
	MVI	A,LF
	CALL	PCHAR
	RET
;
PRINT:	;PRINT MESSAGE IN D,E 'TIL FIRST ZERO
	LDAX	D
	ORA	A
	RZ
;	MORE TO PRINT
	INX	D
	PUSH	D
	CALL	PCHAR
	POP	D
	JMP	PRINT
;
;	PRINCIPAL PROCESSORS
SETUP:	;ARRIVE HERE FROM THE RELOCATOR, SET UP JUMPS
	LHLD	BDOSE+1	;PRIMARY ENTRY TO BDOS
	SHLD	HISTO+1	;CHANGE JUMP AT BASE OF THIS MODULE
	LXI	H,HISTO	;CHANGE BDOS ENTRY ADDRESS
	SHLD	BDOSE+1	;INITIAL JUMP ADDRESS CHANGED
;
;	THE PRIMARY BDOS ENTRY ADDRESS NOW REFLECTS THE ADDITION
;	OF THE TRACE MODULE, THE SYMBOL TABLE HAS BEEN INCLUDED
;	AT THE BEGINNING OF THE MODULE, AND ITS LENGTH WILL BE
;	RETURNED WITH THE "INITIAL" CALL IN REGS DE
	JMP	INITIAL
;
INERR:	LXI	D,ERMSG
	CALL	PRINT
;
INITIAL:
	LXI	D,BOUNDS	;SEND STARTING MESSAGE
	CALL	PRINT
	CALL	GETBUFF		;GET BUFFER FULL FOR BOUNDS SCAN
	CALL	SCANEXP		;SHOULD BE 2 PARAMETERS
	JC	INERR		;CANNOT BE ,X,X
	CPI	2
	JNZ	INERR		;1,3?
	CALL	GETVAL		;FIRST PARAMTER TO H,L
	SHLD	LB		;LOWER BOUND SAVED
	PUSH	H		;COMPARED WITH UPPER BOUND LATER
	CALL	GETVAL		;UPPER BOUND
	INX	H
	SHLD	UB
	POP	D		;LOWER IN D,E UPPER IN H,L
	XCHG
	CALL	DIFF		;UB>=LB?
	JC	INERR
;	DIFFERENCE IN D,E - COMPUTE INCREMENT
	XCHG
	CALL	SHR6		;DIVIDE BY 64
	SHLD	INC
	LXI	H,HVEC		;CLEAR THE HISTGRAM VECTOR
	MVI	C,HSIZE*2
FILL0:	MVI	M,0
	INX	H
	DCR	C
	JNZ	FILL0
;	VECTOR FILLED, GO BACK TO THE DEBUGGER
	LXI	D,INIMSG
	CALL	PRINT
	LXI	D,INIE
	CALL	PADDR		;INITIAL = XXXX
	LXI	D,COLMSG
	CALL	PRINT
	LXI	D,COLE
	CALL	PADDR		;COLLECT = XXXX
	LXI	D,DISMSG
	CALL	PRINT
	LXI	D,DISE
	CALL	PADDR		;DISPLAY = XXXX
	LXI	D,SYLEN		;NUMBER OF SYMBOLS
	RET
;
;
;
COLLECT:
;	CALLED FROM DEBUGGER WITH REGISTER C HOLDING THE OPERATOR
;	CATEGORY (NOT USED HERE), AND D,E HOLDING THE PC
	PUSH	D	;SAVE THE PC
	LHLD	UB	;WITHIN THE RANGE LB - UB?
	XCHG
	CALL	DIFF	;X = UB - PC
	POP	D
	JC	RET0	;SKIP IF BELOW LB
	LHLD	LB
	CALL	DIFF	;X = PC - LB
	JC	RET0
;
;	D,E HAS INDEX TO HIST VECTOR
	MVI	C,0	;READY TO COUND INDEX TO PROPER ELEMENT IN HVEC
	LHLD	INC	;AMOUNT IN EACH CATEGORY
FINDCELL:
	CALL	DIFF	;X = X - INC
	JC	FOUND
	INR	C	;TO NEXT HVEC ELEMENT
	JMP	FINDCELL
;
;	REG C HAS INDEX TO HVECT
FOUND:
	MVI	B,0	;BECOMES DOUBLE PRECISION
	LXI	H,HVEC
	DAD	B
	DAD	B	;HVECT(X)
	MOV	E,M	;OLD VALUE OF HVEC(X)
	INX	H
	MOV	D,M	;TO D,E, READY FOR INCREMENT
	INX	D	;COUNT UP BY ONE, CHECK FOR 0FFFFH
	MOV	M,D
	DCX	H
	MOV	M,E	;REPLACED IN MEMORY
	INX	D	;0FFFFH GOES TO 0000H
	MOV	A,D
	ORA	E
	JNZ	RET0	;NORMAL RETURN IF NOT 0FFFFH
;
;	ONE CATEGORY FILLED, STOP EXECUTION
	MVI	A,1
	RET
;
RET0:	;RETURN 0 TO CONTINUE COLLECTION
	MVI	A,0
	RET
;
;
;
DISPLAY:
;	DISPLAY THE HISTOGRAM COLLECTED SO FAR
;	FIND LARGEST VALUE TO SCAL DIAGRAM
	LXI	H,HVEC
	MVI	C,HSIZE
	LXI	D,0	;MAX SO FAR
LARG0:	PUSH	D	;SAVE LARGEST
	MOV	E,M
	INX	H
	MOV	D,M	;D,E HOLDS TEST ELEMENT
	INX	H	;READY FOR NEXT ELEMENT
	XTHL		;LARGEST TO H,L ADDRESS TO STACK
	PUSH	D	;SAVE TEST
	CALL	DIFF	;X = TEST - LARGEST
	POP	D	;RESTORE TEST VALUE
	XCHG		;LARGEST IN D,E - TEST IN H,L
	JC	LARG1	;CARRY IF LARGEST > TEST
	XCHG		;TEST GOES TO D,E
LARG1:	DCR	C	;COUNT LENGTH DOWN
	POP	H	;RECALL HVEC ADDRESS
	JNZ	LARG0	;FOR ANOTHER TEST
;
;	MAX IS IN D,E
	XCHG		;TO H,L
	PUSH	H	;SAVE LARGEST FOR PRINTING BELOW
	CALL	SHR6	;DIVIDE BY 64 FOR SCALING
	INX	H	;IN CASE OF REMAINDER
	SHLD	SCALE
	LXI	D,LARMSG
	CALL	PRINT
	POP	D	;RECALL LARGEST VALUE
	CALL	PADDR
	XRA	A	;CLEAR ZERCNT
	STA	ZERCNT
;
;	NOW STEP THROUGH THE HIST VECTOR AND PRINT '*' FOR EACH LINE
	LHLD	LB
	XCHG		;LOWER BOUND TO D,E
	LXI	B,HVEC	;BASE OF HIST VECTOR
DISP0:	PUSH	D	;SAVE CURRENT LINE ADDRESS
	LHLD	UB	;TEST FOR OVER THE TOP
	CALL	DIFF
	POP	D
	JNC	DISP1	;NO CARRY IF CURRENT >= UB
;	CHECK FOR MULTIPLE BLANK LINES AND PRINT .... INSTEAD
	MOV	H,B	;HIGH ORDER HVEC INDEX
	MOV	L,C	;LOW ORDER HVEC INDEX
	MOV	A,M	;LOW ORDER HVEC VALUE
	INX	H
	ORA	M	;VALUE = 0?
	LXI	H,ZERCNT
	JNZ	ZCHK1	;VALUE IS NOT ZERO, PRINT LINE
;	VALUE IS ZERO, ALREADY PRINTED?
	MOV	A,M	;GET ZERCNT
	ORA	A
	JNZ	ZCHK0	;JUMP IF ALREADY PRINTED LINE
;	NOT PRINTED YET, SET ZERCNT TO TRUE AND PRINT MSG
	MVI	M,0FFH
	PUSH	B
	PUSH	D
	LXI	D,PERMSG
	CALL	PRINT
	POP	D
	POP	B
ZCHK0:	;INCREMENT LINE ADDRESS
	LHLD	INC
	DAD	D
	XCHG
;	INCREMENT HVEC ADDRESS
	INX	B
	INX	B
	JMP	DISP0
;
ZCHK1:	;LINE IS NOT ZERO, FLAG IT AND CONTINUE
	MVI	M,0	;ZERCNT SET FALSE
	PUSH	B	;INDEX TO HVEC SAVED
	PUSH	D	;CURRENT LINE SAVED
	PUSH	D	;ANOTHER COPY
	CALL	CRLF
	POP	D	;LINE ADDRESS TO DE
	CALL	PADDR	;PRINTED
	POP	D	;RECALL LINE ADDRESS
	LHLD	INC	;INCREMENT BETWEEN LINES
	DAD	D
	XTHL		;LINE ADDRESS STACKED, INDEX TO HVEC IN HL
	MOV	E,M
	INX	H
	MOV	D,M
	INX	H
	PUSH	H	;SAVE UPDATED HVEC ADDRESS
	CALL	STARS	;PRINTS STARS FOR THIS LINE
	POP	B	;RECALL HVEC BASE
	POP	D	;RECALL CURRENT LINE
	JMP	DISP0
;
DISP1:	;END OF DISPLAY
	CALL	CRLF
	RET		;RETURN TO DDT
;
STARS:	;PRINT STARS ACROSS LINE BASED ON SCALE VALUE
	MOV	A,E
	ORA	D
	RZ		;RETURN IF ZERO STARS
	PUSH	D
	MVI	A,' '
	CALL	PCHAR
;
	POP	D
STAR0:	;LOOP PRINTING STARS
	LHLD	SCALE	;SCALING FACTOR
	CALL	DIFF	;X = SIZE - SCALE
	RC
	PUSH	D	;SAVE REMAINING LENGTH
	MVI	A,'*'
	CALL	PCHAR
	POP	D
	JMP	STAR0
;
;
;	DATA AREAS
ERMSG:	DB	CR,LF,'ERROR - FORM IS X,Y',0
BOUNDS:	DB	CR,LF,'TYPE HISTOGRAM BOUNDS ',0
LARMSG:	DB	CR,LF,'HISTOGRAM:'
	DB	CR,LF,'ADDR      RELATIVE FREQUENCY, LARGEST VALUE = ',0
INIMSG:	DB	CR,LF,'.INITIAL = ',0
COLMSG:	DB	CR,LF,'.COLLECT = ',0
DISMSG:	DB	CR,LF,'.DISPLAY = ',0
PERMSG:	DB	CR,LF,'....',0
ZERCNT:	DS	1
LB:	DS	2	;LOWER BOUND
UB:	DS	2	;UPPER BOUND
HVEC:	DS	HSIZE*2	;HISTOGRAM VECTOR
SCALE:	DS	2	;SCALE FACTOR
INC:	DS	2	;INCREMENT BETWEEN LINES
	NOP
	END	HISTO
