;**************************************************************
; MITS CHECKSUM LOADER FOR 8K ALTAIR BASIC VERSION 4.X        *
;  DISASSEMBLED BY MARTIN EBERHARD 13 DECEMBER 2010           *
;  MODIFIED TO REPLACE HSR PORT WITH 2SIO PORT 1 10 JAN 2011  *
;  COMMENTS FIXED, A FEW 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	FALSE	;ALTAIR 4K BASIC
BAS8K	EQU	FALSE	;ALTAIR 8K BASIC
BASEX	EQU	TRUE	;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
S2CTL1	EQU	12H	;ACIA 1 CONTROL OUTPUT PORT
S2STA1	EQU	12H	;ACIA 1 STATUS INPUT PORT
S2TXD1	EQU	13H	;ACIA 1 TX DATA REGISTER
S2RXD1	EQU	13H	;ACIA 1 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
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	20H		;PORT 0 SECTION A CTRL/STATUS
P4DA0	EQU	21H		;PORT 0 SECTION A DATA
P4CB0	EQU	22H		;PORT 0 SECTION B CTRL/STATUS
P4DB0	EQU	23H		;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	10000000B	;RX DATA REG FULL
;--------------------------------------------------------------
; 88-PIO EQUATES
;--------------------------------------------------------------
; 88-PIO REGISTERS	

PIOCTL	EQU	4		;CONTROL PORT
PIOSTA	EQU	4		;STATUS
PIOTXD	EQU	5		;TRANSMIT DATA
PIORXD	EQU	5		;RECEUVE DATA

;STATUS REGISTER BITS

PIORDF	EQU	00000010B	;RX DATA REG FULL
;--------------------------------------------------------------
; 88-HSR (HIGH SPEED TAPE READER) EQUATES
;--------------------------------------------------------------
; 88-HSR REGISTERS	

HSRCTL	EQU	24H		;CONTROL PORT
HSRSTA	EQU	24H		;STATUS
HSRTXD	EQU	25H		;TRANSMIT DATA
HSRRXD	EQU	25H		;RECEUVE DATA

;STATUS REGISTER BITS

HSRRDF	EQU	01000000B	;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

;--------------------------------------------------------------
; INITIALIZE PORTS THAT MIGHT BE NEEDED FOR PRINTING ERROR
; MESSAGES. NOTE THAT THE LOAD PORT WILL ALREADY HAVE BEEN
; INITIALIZED BY THE BOOTSTRAP LOADER.
;--------------------------------------------------------------
;RESET THE 4PIO

; 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

; 4PIO: SETUP FOR READY BIT SET ON E PULSE, CLEARED AFTER DATA
; READ, DE-SELECT DDR REGISTER

	MVI	A,P4C25+P4C23+P4DDR
	OUT	P4CB0

; MASTER-RESET ONLY PORT0 OF THE 2SIO (THE BOOTSTRAP LOADER WILL
; ALREADY HAVE INITIALIZED PORT 1 IF IT IS THE LOAD PORT.)

	MVI	A,S2RST	;MASTER RESET FOR 2SIO
	OUT	S2CTL0

; GET 2SIO PORT 0 STOP BITS FROM FRONT PANEL, INIT 2SIO PORT 0

	IN	SWTCHS
	ANI	10H		;SWITCH A12 SPECIFIES STOP BITS
	RRC
	RRC			;PUT IN PLACE FOR S2WS1
	ADI	S2DS1+S2WS3
	OUT	S2CTL0		;INITIALIZE ACIA0

;--------------------------------------------------------------
; SET UP STACK
;--------------------------------------------------------------
	LXI	SP,LSTACK
;--------------------------------------------------------------
; GET LOAD PORT ASSIGNMENT FROM FRONT PANEL SWITCHES, AND
; MODIFY THE GETBYT SUBROUTINE FOR THE ASSIGNED PORT
;--------------------------------------------------------------
; GET FRONT PANEL SETTING, STRIP AND TEST LOAD PORT BITS

	IN	SWTCHS
	ANI	0FH		;GET LOAD PORT ASSIGNMENT
	CPI	7
	JP	LPERR		;>=7 MEANS UNSUPPORTED PORT

; LOOKUP LOAD PORT PARAMATERS AND PASTE THEM INTO THE GENERIC
; TAPE INPUT SUBROUTINE

	LXI	H,LPTABL	;LOAD PORT TABLE BASE ADDRESS

	MVI	B,0		;HIGH BYTE FOR DAD	
	MOV	C,A		;A=A*3 (TABLE AS 3 BYTES/ENTRY)
	ADD	A
	ADD	C

	MOV	C,A		;BC=3*FRONT PANEL LOAD PORT BITS
	DAD	B		;HL=ADDR OF CORRECT TABLE ENTRY

	MOV	A,M		;GET DATA PORT ADDRESS
	STA	DPORT		;MODIFY CODE

	DCR	A		;COMPUTE CTRL/STAT PORT ADDRESS
	STA	CSPORT		;MODIFY CODE

	INX	H
	MOV	A,M		;GET EITHER JZ OR JNZ
	STA	JZJNZ		;MODIFY CODE

	INX	H
	MOV	A,M		;GET RX DATA AVAILABLE BIT
	STA	RDABIT		;MODIFY CODE
;--------------------------------------------------------------
; 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	GETBYT		;GET A BYTE FROM THE TAPE
	MOV	C,A		;LOW BYTE OF GO ADDRESS

	CALL	GETBYT		;GET ANOTHER TAPE BYTE

	MOV	L,C		;LOW BYTE OF ADDRESS
	MOV	H,A		;HIGH BYTE OF ADDRESS

	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	GETBYT		;GET TAPE BYTE
	MOV	E,A		;E GETS LOW BYTE OF ADDRESS

	CALL	GETBYT		;ANOTHER TAPE BYTE
	MOV	D,A		;DE=LOAD ADDRESS

; 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:	MOV	A,D		;WILL THIS BYTE OVERWRITE US?
	CPI	(MSIZE-100H)/256
	MVI	A,'O'		;OVERRUN ERROR MESSAGE
	JZ	ERROR

	CALL	GETBYT		;GET A DATA BYTE

	XCHG			;HL HAS LOAD ADDRESS
	MOV	M,A		;WRITE BYTE TO MEMORY
	CMP	M		;VERIFY WRITE
	MVI	A,'M'		;MEMORY ERROR MESSAGE
	JNZ	ERROR		;MEMORY WRITE ERROR

	INX	H		;NEXT ADDRESS
	XCHG

	DCR	C		;BUMP BYTE COUNT
	JNZ	BYTLUP

; 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
;--------------------------------------------------------------
; LOAD PORT ERROR: ILLEGAL LOAD PORT SPECIFIED ON FRONT PANEL
;--------------------------------------------------------------
LPERR:	MVI	A,'I'		;ILLEGAL LOAD PORT ERROR MSG
;	FALL INTO ERROR

;**************************************************************
; ERROR ROUTINE: PRINT VALUE IN A TO ALL PORTS OVER AND
; OVER, WITHOUT EVEN TESTING FOR TX BUFFER EMPTY
;**************************************************************

ERROR:	STA	0000H		;REMEMBER ERROR CODE
	SHLD	0001H		;REMEMBER ADDRESS OF ERROR?

	EI			;RE-ENABLE INTERRUPTS

;LOOP TO PRINT ERROR MESSAGE CONTINOUOSLY TO ALL PORTS

ERRLUP:	OUT	SIOTXD		;SIO PORT
	OUT	S2TXD0		;2SIO PORT 0
	OUT	PIOTXD		;PIO PORT
	OUT	P4DB0		;4PIO PORT

	JMP	ERRLUP

;**************************************************************
; 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		;CTRL/STAT PORT (GETS MODIFIED)

	DB	ANI		;TEST READER DATA AVAIL BIT
RDABIT:	DB	0		;GETS MODIFIED

JZJNZ:	JZ	GETBYT		;INSTRUCTION GETS MODIFIED

	DB	IN		;GET DATA FROM PORT
DPORT:	DB	0		;DATA PORT (GETS MODIFIED)

; COMPUTE CHECKSUM

	PUSH	PSW
	ADD	B
	MOV	B,A
	POP	PSW

	RET

;**************************************************************
; LOAD PORT PARAMETER TABLE. EACH ENTRY IS 3 BYTES:
; BYTE 0: DATA PORT ADDRESS
; BYTE 1: JZ/JNZ FOR DA BIT TEST
; BYTE 2: DATA AVAILABLE BIT MASK
;**************************************************************

LPTABL:	DB	S2RXD0,JZ,S2RDF	;0=2SIO PORT0, 2 STOP BITS
	DB	S2RXD0,JZ,S2RDF	;1=2SIO PORT0, 1 STOP BIT	
	DB	SIORXD,JNZ,SIOIDR	;2=SIO PORT
	DB	ACRRXD,JNZ,ACRIDR	;3=ACR PORT (CASSETTE)
	DB	P4DA0,JZ,P4RDF	;4=4PIO PORT
	DB	PIORXD,JZ,PIORDF	;5=PIO PORT
;	DB	HSRRXD,JZ,HSRRDF	;6=HSR PORT (HI-SPEED RDR)
	DB	S2RXD1,JZ,S2RDF	;6=2SIO PORT1

	DB	0

;**************************************************************
; LOCAL STACK
;**************************************************************

	ORG	MSIZE
LSTACK:	EQU	$

	END

