;
; TARBELL ELECTRONICS CP/M DE-BLOCK COLDSTART LOADER.
; DMA VERSION
; version of 10-06-81.
; for deblocked operating system only
; modified for tarbell cpu card  -  7-3-80.
; modified for deblock   3-21-81
; modified for head loaded check - 10-6-81
; removed dma code (never worked) - 6-9-81
; added code to clear extended latch 6-26-81
; g.w.mulchin
; added dma code again on 9-15-81 (D.T.)
; ADDED BOOTSTRAP RELOCATION CODE 8-10-82
; EDWIN E. SMITH
; ADDED CPM PAGE SIZING OPTION 8-13-82
; CONSOLIDATED DMA & NON DMA LOADERS 8-17-82
; EDWIN E. SMITH
; tarbell electronics
;-------------------------------------------------
; copyright (c) 1980 tarbell electronics
;
; this program is loaded at location zero by the
; bootstrap program, and executed. its purpose
; is to load and execute the cp/m disk
; operating system at the top of the memory in use.
;
FALSE	EQU  0000H
TRUE	EQU  NOT FALSE	;define value of true.
;
;********* this is the area to make changes in ***********
;********* for different system configurations ***********
; To locate cpm on a page boundry instead of a kbyte	**
; boundry set PGS EQU to 1,2 or 3 for example a 61.5	**
; kbyte cp/m would have MSIZE EQU to 61 and PGS EQU	**
; to 2 . (see digital research AN-9, 9/29/81)		**
;							**
MSIZE	EQU  63		;memory size in decimal kbytes.	**
PGS	EQU  0		;additional pages for cpm size	**
;							**
MAC	EQU  FALSE	;true if using macro assembler	**
TARBELL	EQU  TRUE	;true if using tarbell cpu.	**
DUBSID	EQU  FALSE	;true for double sided systems.	**
DELTA	EQU  FALSE	;true if using delta cpu card	**
DMA	EQU  FALSE	;TRUE IF USING DMA		**
BASE	EQU  0		;tarbell i/o ports (00 or10 hex)**
SPT	EQU  26		;number of sectors per track.	**
;							**
; *** WARNING - 3200 BYTES WILL BE READ FROM TRACK 0    **
; SIDE 0 AND 512 BYTES FOR EACH SECTOR FROM TRACK 0	**
; SIDE 1, CARE MUST BE EXERCISED TO SEE THAT THE CODE	**
; DOES NOT WRAP AROUND AND EAT THE BOOT PROGRAM		**

MOVE	EQU  FALSE	;TRUE IF SELF MOVING BOOTSTRAP	**
; CAN'T USE MOVE AND DMA AT THE SAME TIME-TO MUCH CODE	**
;							**
DDS	EQU  9		;sectors trk 1 (rng = 8 to 16)	**
;
DISK	EQU  0F8H	;disk port base address.	**
DMAAD	EQU  DISK-18H	;dma address port.		**
DMAWC	EQU  DISK-17H	;dma word count port.		**
DMAC	EQU  DISK-10H	;dma command port.		**
;							**
;*********************************************************
;
	IF	MAC
	MACLIB	Z80
	ENDIF
;
	IF   TARBELL
IO	EQU  BASE	;i/o ports on tarbell cpu.
MMENB	EQU  IO+10	;memory management enable port.
MEMMAG	EQU  BASE+32	;memory management port.
	ENDIF

DCOM	EQU  DISK	;command port.
DSTAT	EQU  DISK	;status port.
SECT	EQU  DISK+2	;sector port.
DATA	EQU  DISK+3	;DATA PORT
DCONT	EQU  DISK+4	;control port.
WAIT	EQU  DISK+4	;WAIT PORT.
EXTMEM	EQU  DISK+5	;extended latch port
DMACHK	EQU  EXTMEM	;1793 interrupt line port
CBASE	EQU  ((MSIZE-20)*1024)+PGS*256
CPMB	EQU  CBASE+3400H;start of cp/m.
BOOTE	EQU  CPMB+1600H	;cold boot entry point.
SDS	EQU  25		;always 25 sectors to read in trk 0.
NSECTS	EQU  SDS + DDS	;sectors of cp/m.
RTCNT	EQU  10		;number of retrys.
;
	ORG  0		;start of loader.

	IF   MOVE AND (NOT DMA)	;MOVES CODE TO 200 HEX
MOVTO	EQU  0200H
	LXI  B,LAST-BOOT	;BYTE COUNT
	LXI  H,MVSTRT	;MOVE FROM
	LXI  D,MOVTO	;MOVE TO
	LDIR		;DO IT
	JMP  MOVTO	;EXECUTE THE BOOT
MVSTRT	EQU  $
OFFSET	EQU  MOVTO-MVSTRT	;OFFSET FOR JUMPS & CALLS
	ELSE
OFFSET	EQU  0		;NO OFFSET IF NOT MOVING
	ENDIF
;
BOOT:
; Load memory-management table.
;
	IF   TARBELL	;if using tarbell cpu
	LXI  B,16 SHL 8 OR MEMMAG
	MVI  A,0FFH
MLOOP:	OUTP A		;send a by way of port c
	DCR  A		;next init byte
	INR  C		;bump port
	DJNZ MLOOP	;decrease count and loop
	OUT  MMENB	;enable memory management.
	ENDIF
;
	IF   DELTA	;if using delta cpu.
	MVI  A,1	;get a 1 in reg a.
	OUT  9		; and disable cpu rom slot.
	ENDIF
;
; Initialize Registers.
; B = retry count (initialized in READ routine).
; C = 1793 command code to read a sector.
; D = number of sectors left to read.
; E = sector number.
; HL = memory address to put sector.
;
	XRA  A		;get a zero
	OUT  EXTMEM	;clear the latch on disk board
	LXI  SP,100H	;set stack pointer.
	LXI  H,CPMB	;cp/m starts here.
	LXI  D,NSECTS SHL 8 OR 2 ;# of sects to read, START SECT.
RNTRK:	MVI  C,88H	;for head load.
RNSEC:	CALL READ+OFFSET	;read first sector.
	DCR  D		;dec sectors to read.
	JZ   BOOTE	;go to cp/m if no more.
	INR  E		;increment sector number.
	MOV  A,E	;done with
	CPI  SPT+1	;this track?
	JRC  RNSEC	;if not, read next sector.
;
	IF NOT DUBSID	;if not double sided.
	MVI  A,8H	;set doub dens code
	OUT  DCONT	;set latch for d.density
	MVI  A,5BH	;step command.
	OUT  DCOM	;issue it.
	IN   WAIT	;wait until done.
	ENDIF
;
	IF   DUBSID	;if double sided system.
	MVI  A,48H	;set doub dens & side select command.
	OUT  DCONT	;issue it.
	ENDIF
;
	MVI  E,1	;sector number.
	JMPR RNTRK	;read next track.
;
; READ sector E from current track into memory at HL.
;
READ:	MVI  B,RTCNT	;get retry count.
	MOV  A,E	;get sector number and
	OUT  SECT	;put into sector register.
	IF   DMA
	MOV  A,D	;get sectors left to read.
	PUSH D		;save DE.
	CPI  DDS+1	;less than sectors on trk 1?
	LXI  D,007FH	;count for 128 byte sectors.
	JRNC READR	;hop if still on track 0.
	LXI  D,01FFH	;count for 512 byte sectors.
READR:	XRA  A		;Clear DMA command register.
	OUT  DMAC
	MOV  A,E	;get least sig byte of count.
	OUT  DMAWC
	MOV  A,D	;get most sig byte of count.
	ORI  40H	;set for dma read operation.
	OUT  DMAWC
	MOV  A,L	;get least sig byte of adr.
	OUT  DMAAD
	MOV  A,H	;get most sig byte of adr.
	OUT  DMAAD
	MVI  A,41H	;activate channel 0.
	OUT  DMAC
	ENDIF
	MOV  A,E	;GET SECTOR #
	DCR  A		;CHECK FOR SECTOR 1
	MVI  A,4	;TO SET 'E' BIT
	JRZ  NOLOAD	;SECTOR 1 ASSUME HEAD NOT LOADED
	XRA  A		;CLEAR 'E' BIT
NOLOAD:	ORA  C		;get head load command
	OUT  DCOM	;issue command.
;
	IF   DMA
;
; Wait until transfer is complete.
;
WAITL:	IN   DMACHK	;read 1793 interrupt line.
	RLC		;is it done yet?
	JRC  WAITL	;loop back if not.
;
; See if there were any errors.
;
	IN   DSTAT	;read status.
	ANI  9DH	;look at error bits.
	JRZ  READE	;exit READ routine.
	DJNZ READ	;decrement and try again if not zero.
	JMPR $		;loop forever at this location
;
; Figure new HL and exit READ routine.
;
READE:	INX  D		;Correct for dumb counter.
	DAD  D		;Add byte count to adr in HL.
	POP  D		;Restore DE.
	RET		;Return from READ routine.
	ELSE
RLOOP:	IN   WAIT	;wait for drq.
	ORA  A		;set flags.
	JP   CHECK+OFFSET	;jump if done.
	IN   DATA	;read data.
	MOV  M,A	;put in memory.
	INX  H		;increment pointer.
	JMPR RLOOP	;loop until done.
;
CHECK:	IN   DSTAT	;read status.
	ANI  9DH	;look at error bits.
	RZ		;RETURN IF OK
	DJNZ READ	;DECREMENT AND TRY AGAIN IF NOT ZERO
	JMPR $		;LOOP FOREVER AT THIS LOCATION
	ENDIF
LAST	EQU  $
;

;
	ORG  7DH
	RST  0		;jump to loc. 0
;
	IF   NOT DUBSID
	DB   0DEH
	DB   0
	ENDIF
;
	IF   DUBSID
	DB   0DCH
	DB   0
	ENDIF
;
	END   BOOT	;end of boot.
	TITLE	'DBBOOT secondary coldstart loader  4-8-81'
