;**************************************************************
; MITS CHECKSUM LOADER FOR 4K ALTAIR BASIC VERSION 3.2 +      *
;  DISASSEMBLED BY MARTIN EBERHARD 13 DECEMBER 2010           *
;  COMMENTS CORRECTED & LABELS SHORTENED 2 SEP 2013           *
;**************************************************************
TRUE	EQU	0FFFFH
FALSE	EQU	0
;--------------------------------------------------------------
; BASIC SIZE OPTION
; EXACTLY ONE OF THE BASIC OPTIONS BELOW MUST BE TRUE
;--------------------------------------------------------------
BAS4K	EQU	TRUE	;ALTAIR 4K BASIC
BAS8K	EQU	FALSE	;ALTAIR 8K BASIC
BASEX	EQU	FALSE	;ALTAIR EXTENDED BASIC
;--------------------------------------------------------------
; ALTAIR EQUATES
;--------------------------------------------------------------
SWTCHS	EQU	0FFH	;FRONT PANEL SWITCH REGISTER
;--------------------------------------------------------------
; ALTAIR FILE EQUATES
;--------------------------------------------------------------
ALTPLR	EQU	3CH	;PROGRAM LOAD RECORD
ALTEOF	EQU	78H	;EOF/GO ADDRESS RECORD
ALTBNR	EQU	55H	;BEGIN/PROGRAM NAME (NOT SUPPORTED)
ALTBND	EQU	0DH	;END-OF-NAME MARK (NOT SUPPORTED)
;--------------------------------------------------------------
; 88-2SIO EQUATES
;--------------------------------------------------------------
; 88-2SIO REGISTERS

S2CTL0	EQU	10H	;ACIA 0 CONTROL OUTPUT PORT
S2STA0	EQU	10H	;ACIA 0 STATUS INPUT PORT
S2TXD0	EQU	11H	;ACIA 0 TX DATA REGISTER
S2RXD0	EQU	11H	;ACIA 0 RX DATA REGISTER

; ACIA CONTROL REGISTER BITS

S2DS1	EQU	00000001B	;COUNTER DIVIDE SEL 1
S2DS2	EQU	00000010B	;COUNTER DIVIDE SEL 2
S2WS1	EQU	00000100B	;WORD SELECT 1
S2WS2	EQU	00001000B	;WORD SELECT 2
S2WS3	EQU	00010000B	;WORD SELECT 3
S2TC1	EQU	00100000B	;TX CONTROL 1
S2TC2	EQU	01000000B	;TX CONTROL 2
S2RIE	EQU	10000000B	;RX INT ENABLE

S2RST	EQU	00000011B	;MASTER RESET

; ACIA STATUS REGISTER BITS

S2RDF	EQU	00000001B	;RX DATA REG FULL
S2TDE	EQU	00000010B	;TX DATA REG EMPTY
S2DCD	EQU	00000100B	;DATA CARRIER DETECT
S2CTS	EQU	00001000B	;CLEAR TO SEND
S2FE	EQU	00010000B	;FRAMING ERROR
S2ORE	EQU	00100000B	;RX OVERRUN ERROR
S2PE	EQU	01000000B	;PARITY ERROR
S2IRQ	EQU	10000000B	;INTERRUPT REQUEST
;--------------------------------------------------------------
; 88-SIO EQUATES
;--------------------------------------------------------------
; 88-SIO REGISTERS	

SIOCTL	EQU	0		;CONTROL PORT
SIOSTA	EQU	0		;STATUS
SIOTXD	EQU	1		;TRANSMIT DATA
SIORXD	EQU	1		;RECEUVE DATA

;STATUS REGISTER BITS

SIOIDR	EQU	00000001B	;INPUT DEV RDY (RX BUF FULL)
SIOPE	EQU	00000100B	;PARITY ERROR
SIOFE	EQU	00001000B	;FRAMING ERROR
SIODOV	EQU	00010000B	;DATA OVERFLOW
SIODA	EQU	00100000B	;RX DATA AVAILABLE
				; (UNMODIFIED SIO ONLY)
SIOODR	EQU	10000000B	;OUTPUT DEV RDY (TX BUF EMPTY)
;--------------------------------------------------------------
; 88-ACR (AUDIO CASSETTE RECORDER) EQUATES
; NOTE: THE ALTAIR ACR IS BUILT AROUND AN ALTAIR 88-SIO
;--------------------------------------------------------------
; 88-ACR REGISTERS	

ACRCTL	EQU	6		;CONTROL PORT
ACRSTA	EQU	6		;STATUS
ACRTXD	EQU	7		;TRANSMIT DATA
ACRRXD	EQU	7		;RECEUVE DATA

;STATUS REGISTER BITS

ACRIDR	EQU	00000001B	;INPUT DEV RDY (RX BUF FULL)
ACRPE	EQU	00000100B	;PARITY ERROR
ACRFE	EQU	00001000B	;FRAMING ERROR
ACRDOV	EQU	00010000B	;DATA OVERFLOW
ACRODR	EQU	10000000B	;OUTPUT DEV RDY (TX BUF EMPTY)
;--------------------------------------------------------------
; 88-4PIO EQUATES
;--------------------------------------------------------------
; 88-4PIO REGISTERS	

P4CA0	EQU	10H		;PORT 0 SECTION A CTL/STATUS
P4DA0	EQU	11H		;PORT 0 SECTION A DATA
P4CB0	EQU	12H		;PORT 0 SECTION B CTL/STATUS
P4DB0	EQU	13H		;PORT 0 SECTION B DATA

;CONTROL REGISTER BITS

P4C10	EQU	00000001B	;C1 CONTROL BIT 0
P4C11	EQU	00000010B	;C1 CONTROL BIT 1
P4DDR	EQU	00000100B	;DATA DIRECTION REGISTER
P4C23	EQU	00001000B	;C2 CONTROL BIT 3
P4C24	EQU	00010000B	;C2 CONTROL BIT 4
P4C25	EQU	00100000B	;C2 CONTROL BIT 5
P4IC2	EQU	01000000B	;C2 INTERRUPT CONTROL
P4IC1	EQU	10000000B	;C1 INTERRUPT CONTROL BIT

;STATUS REGISTER BITS

P4RDF	EQU	01000000B	;RX DATA REG FULL
;--------------------------------------------------------------
; 88-PIO EQUATES
;--------------------------------------------------------------
; 88-PIO REGISTERS	

PIOCTL	EQU	0		;CONTROL PORT
PIOSTA	EQU	0		;STATUS
PIOTXD	EQU	1		;TRANSMIT DATA
PIORXD	EQU	1		;RECEUVE DATA

;STATUS REGISTER BITS

PIORDF	EQU	00000010B	;RX DATA REG FULL
;--------------------------------------------------------------
; COMPUTE ADDRESS BASE
;--------------------------------------------------------------

IF BAS4K
MSIZE	EQU	1000H
ENDIF

IF BAS8K
MSIZE	EQU	2000H
ENDIF

IF BASEX
MSIZE	EQU	4000H
ENDIF

;**************************************************************
;BEGIN CODE
;**************************************************************
	ORG	MSIZE-100H	;TOP OF KNOWN MEMORY

	DI
;--------------------------------------------------------------
; SET UP STACK
;--------------------------------------------------------------
	LXI	SP,LSTACK

;--------------------------------------------------------------
; GET LOAD PORT SETTING FROM FRONT PANEL SWITCHES
; SET B TO CONTROL PORT ADDRESS
; SET H TO JZ OR JNZ FOR DATA AVAILABLE TEST
; SET L TO DATA AVAILABLE BIT MASK
;--------------------------------------------------------------
	IN	SWTCHS

	MVI	H,JZ
	MVI	B,SIOCTL

	RAL		;SWITCH 15 SET MEANS ACR
	JC	SETACR

	RAL		;SWITCH 14 MEANS UNMODIFIED SIO
	MVI	L,SIODA
	JC	SETPRT

	RAL		;SWITCH 13 MEANS PIO AT ADDRESS 0
	MVI	L,PIORDF
	JC	SETPRT


	MVI	B,P4CA0
	RAL		;SWITCH 12 MEANS 4PIO PORT 0 SECT A
	JC	ST4PIO

	RAL		;SWITCH 11 MEANS 2SIO PORT 0
	DCR	L	;L=01H
	JC	SETPRT

	MVI	B,SIOCTL ;NO SWITCHES MEANS MODIFIED SIO

	DB	JC	;JC OPCODE: SKIP 2 ADDRESSES

SETACR:	MVI	B,ACRSTA

	LXI	H,JNZ*256+ACRIDR
	JMP	SETPRT

;--------------------------------------------------------------
; INITIALIZE 4PIO PORT
;--------------------------------------------------------------
ST4PIO:	MVI	L,P4RDF

; 4PIO: DISABLE INTERRUPTS, CONTROL SIGNALS ACTIVE-LOW,
; ACCESS DDR REGISTER

	XRA	A
	OUT	P4CB0

; 4PIO: SET ALL BITS OF B PORT FOR INPUT BY WRITING TO DDR REG

	CMA
	OUT	P4DB0

; DE-SELECT DDR REGISTER, SELECT DATA REGISTER

	MVI	A,P4DDR
	OUT	P4CB0

;	FALL INT SETPRT

;--------------------------------------------------------------
; MODIFY GETBYT ROUTINE
; B = CONTROL PORT ADDRESS
; H = JZ OR JNZ FOR DATA AVAILABLE TEST
; L = DATA AVAILABLE BIT MASK
;--------------------------------------------------------------
SETPRT:	MOV	A,B	;GET CONTROL PORT ADDRESS
	SHLD	RDABIT	;MODIFY BOTH BIT MASK AND JZ/JNZ

	STA	CSPORT	;MODIFY CONTROL/STATUS PORT
	INR	A	;DATA PORT ADDRESS
	STA	DPORT	;MODIFY CONTROL PORT

;--------------------------------------------------------------
; HUNT FOR EITHER A PROGRAM RECORD OR AN EOF RECORD
;--------------------------------------------------------------
HUNT:	CALL	GETBYT		;GET A BYTE FROM THE TAPE

	CPI	ALTPLR		;PROGRAM RECORD?
	JZ	PRGREC		;YES: GO GET DATA

	CPI	ALTEOF		;END OF FILE?
	JNZ	HUNT		;IGNORE ALL OTHER CHRS	

; EOF RECORD FOUND. GET EXECUTION ADDRESS AND GO THERE

	CALL	GETADR		;GET 16-BIT ADDRESS INTO HL
	PCHL			;GO TO SPECIFIED ADDRESS

;--------------------------------------------------------------
; GET & VALIDATE PROGRAM RECORD DATA, SAVE IT WHERE IT GOES
;--------------------------------------------------------------
PRGREC:	CALL	GETBYT		;GET THIS RECORD'S BYTE COUNT
	MOV	C,A		;C GETS BYTE COUNT
	MVI	B,0		;CHECKSUM STARTS AT 0

; GET THIS PROGRAM RECORD'S LOAD ADDRESS

	CALL	GETADR		;GET 16-BIT ADDRESS INTO HL

; LOOP TO READ SPECIFIED NUMBER OF DATA BYTES AND STORE THEM
; SEQUENTIALLY STARTING AT THE SPECIFIED LOAD ADDRESS. COMPUTE
; THE CHECKSUM IN B, IN SUBROUTINE GETBYT.

BYTLUP:	CALL	GETBYT		;GET A DATA BYTE

; TEST IF THIS BYTE WILL OVERWRITE THIS CHECKSUM LOADER

	PUSH	H
	LXI	D,0-(MSIZE-100H)
	DAD	D

	JNC	NOOVRW		;NO OVERWRITE

	LXI	D,(MSIZE-100H)-LSTACK ;LAST ADDR OF THIS CODE
	DAD	D
	JNC	OVRERR		;OVERWRITE ERROR
NOOVRW:
	POP	H

	MOV	M,A		;WRITE BYTE TO MEMORY
	CMP	M		;VERIFY WRITE
	JNZ	MEMERR		;MEMORY WRITE ERROR

	INX	H		;NEXT ADDRESS
	DCR	C		;BUMP BYTE COUNT
	JNZ	BYTLUP		;GET MORE UNLESS WE ARE DONE

; GET THE PROGRAM RECORD'S CHECKSUM BYTE AND COMPARE IT TO
; THE COMPUTED CHECKSUM IN B

	MOV	C,B		;C GETS COMPUTED CHECKSUM
	CALL	GETBYT		;A GETS RECORD'S CHECKSUM BYTE
	CMP	C
	JZ	HUNT
;--------------------------------------------------------------
; CHECKSUM ERROR
;--------------------------------------------------------------
	MVI	A,'C'		;CHECKSUM ERROR MESSAGE
	DB	1		;LXI B OPCODE: SKIP 2 BYTES
;--------------------------------------------------------------
; MEMORY READ/WRITE ERROR
;--------------------------------------------------------------
MEMERR:	MVI	A,'M'
	DB	1		;LXI B OPCODE: SKIP 2 BYTES
;--------------------------------------------------------------
; OVERRUN ERROR: ATTEMPT TO WRITE ON TOP OF CHECKSUM LOADER
;--------------------------------------------------------------
OVRERR:	MVI	A,'O'		;ILLEGAL LOAD PORT ERROR MSG

;**************************************************************
; ERROR ROUTINE: PRINT VALUE IN A TO ALL PORTS OVER AND
; OVER, WITHOUT EVEN TESTING FOR TX BUFFER EMPTY
;**************************************************************
ERROR:	OUT	SIOTXD		;SIO PORT
	OUT	S2TXD0		;2SIO PORT 0
	OUT	P4DB0		;4PIO PORT

	JMP	ERROR

;**************************************************************
; SUBROUTINE: GET 16-BIT ADDRESS FROM FILE INTO HL
;**************************************************************
GETADR:	CALL	GETBYT		;GET LOW BYTE
	MOV	L,A
	CALL	GETBYT
	MOV	H,A
	RET

;**************************************************************
; SUBROUTINE: WAIT FOR THEN GET A BYTE FROM THE LOAD PORT.
; NOTE THAT THIS CODE GETS MODIFIED ACCORDING TO THE FRONT
; PANEL SWITCH SETTINGS.
; ON ENTRY:
;    B = CHECKSUM SO FAR
; ON EXIT:
;    A = CHARACTER FROM LOAD PORT
;    B = UPDATED CHECKSUM
;**************************************************************

; WAIT FOR DATA AVAILABLE

GETBYT:	DB	IN
CSPORT:	DB	0		;CTL/STAT PORT (GETS MODIFIED)

	DB	ANI		;TEST READER DATA AVAIL BIT
RDABIT:	DB	01H		;GETS MODIFIED

JZJNZ:	JNZ	GETBYT		;INSTRUCTION GETS MODIFIED

	DB	IN		;GET DATA FROM PORT
DPORT:	DB	01H		;DATA PORT (GETS MODIFIED)

; COMPUTE CHECKSUM

	MOV	D,A
	ADD	B
	MOV	B,A
	MOV	A,D

	RET

;**************************************************************
; LOCAL STACK - ROOM FOR 4 BYTES ON THE STACK
;**************************************************************
SSPACE	DS	4
LSTACK:	EQU	$

	END

