* NEWDISK
*   Disk formatting program for FLEX 2.0
*   This version is for SWTPC 6800 with the
*   Percom LFD-400 floppy controller.
*
*   Created from NEWDISK for the SWTPC DC-1
*   as disassembled by Michael Holley
*
*   Mike Douglas 03/14/20

* TEMPORARY STORAGE

TRACK EQU $0020
SECTOR EQU $0021
BADCNT EQU $0022
DRN EQU $0023 DRIVE NUMBER
SIDE EQU $0024
DBSDF EQU $0025
INDEX1 EQU $0026
INDEX2 EQU $0028
INDEX3 EQU $002A
SECCNT EQU $002C
FSTAVL EQU $002E
LSTAVL EQU $0030

* General equates used in NEWDISK

FIRST  EQU $0101 FIRST USED SECTOR
FCS    EQU 30    FCB CURRENT SECTOR
FSB    EQU 64    FCB SECTOR BUFFER
IRS    EQU 16    INFO RECORD START
AVLP   EQU FSB+IRS+13
DIRSEC EQU 5     FIRST DIR. SECTOR
RDSS   EQU 9     READ SS FMS CODE
WTSS   EQU 10    WRITE SS FMS CODE

* Work space where one track of data is setup

TKSZ   EQU 256*10 SIZE OF SD WORK BUFFER

WORK   EQU $0100 WORK SPACE
SWKEND EQU TKSZ+WORK

TOTSS  EQU 340 TOTAL SECTORS SINGLE SIDED
TOTDS  EQU 680 TOTAL SECTORS DOUBLE SIDED

LASTSS EQU $220A LAST AVAIL SECTOR SS
LASTDS EQU $2214 LAST AVAIL SECTOR DS

MAXTRK EQU 35 NUMBER OF TRACKS

MAXS0  EQU 10 SD MAX SIDE 0 SECTORS
MAXS1  EQU 20 SD MAX SIDE 1 SECTORS

* FLEX LOCATIONS

SSTACK EQU $A07F
SMONTH EQU $AC0E DOS DATE
SDAYMN EQU $AC0F
SYEARN EQU $AC10

* FLEX ROUTINES EQUATES

WARMST EQU $AD03
GETCHR EQU $AD15
PUTCHR EQU $AD18
INBUFF EQU $AD1B
PSTRNG EQU $AD1E
PRCRLF EQU $AD24
GETFIL EQU $AD2D
OUTDEC EQU $AD39
OUTHEX EQU $AD3C
GETHEX EQU $AD42
INDECM EQU $AD48
FMSCAL EQU $B406

* DISK DRIVER ROUTINES

DWRITE EQU $BE83 WRITE A SINGLE SECTOR
DRSTOR EQU $BE89 RESTORE HEAD

 ORG $A100

*************************************************
* MAIN PROGRAM STARTS HERE
*************************************************

STARTR BRA FORM1
VN FCB 1 VERSION NUMBER

FKFCB  FDB $0000,$0000
VOLNAM FDB $0000,$0000,$0000,$0000,$0000
       FCB $00
VOLNUM FDB $0000

FORM1 LDS #SSTACK
 JSR GETHEX GET DRIVE NUMBER
 BCC FORM12 BR IF GOOD NUMBER
FORM11 JMP EXIT
FORM12 STX INDEX3
 LDAA INDEX3+1
 CMPA #3
 BHI FORM11 ENSURE 0 TO 3
 LDX #WORK
 STAA $03,X
 STAA DRN DRIVE NUMBER
 LDX #SURES ARE YOU SURE
 JSR PSTRNG
 JSR GETCHR
 CMPA #'Y
 BNE FORM23
 LDX #SCRDS SCRATCH DISK
 JSR PSTRNG
 LDX #WORK+2
 CLR 0,X
 CLRB 
 JSR OUTDEC PRINT DRIVE NUMBER
 LDAA #'?
 JSR PUTCHR
 LDAA #'  SPACE
 JSR PUTCHR
 JSR GETCHR
 CMPA #'Y
 BEQ FORM24
FORM23 JMP EXIT
FORM24 CLR DBSDF INITALIZE SINGLE SIDED
 BRA FORM25
 LDX #DBST DOUBLE SIDED
 JSR PSTRNG
 JSR GETCHR
 CMPA #'Y
 BNE FORM25
 INC DBSDF
FORM25 LDX #NMSTR NAME
 JSR PSTRNG
 JSR INBUFF GET LINE
 LDX #FKFCB FAKE FCB
 JSR GETFIL
FORM27 LDX #NUMSTR NUMBER
 JSR PSTRNG
 JSR INBUFF
 JSR INDECM
 BCS FORM27 GET GOOD VOLUME NUMBER
 STX VOLNUM
 JSR PRCRLF
 LDX #WORK
 JSR DRSTOR RESTORE DISK
 BCS EXIT
 BNE EXIT4 WRITE PROTECT ERROR

************************************************
* ACTUAL FORMAT ROUTINE

 LDX #WORK
FORM30 CLR 0,X CLEAR RAM BUFFER
 INX 
 CPX #SWKEND
 BNE FORM30
 NOP 
 SEI 
 CLR TRACK
 CLR SIDE

FORM32 LDX #WORK
 TST SIDE
 BNE FORM4
 CLR SECTOR
FORM4 BSR DOSEC PROCESS RAM WITH INFO
 INC SECTOR ADVANCE TO NEXT
 LDAA SECTOR CHECK VALUE
 TST SIDE CHECK SIDE
 BNE FORM45
 CMPA #MAXS0
 BNE FORM4 REPEAT UNTIL LAST SECTOR
 BRA FORM47
FORM45 CMPA #MAXS1
 BNE FORM4 REPEAT UNTIL LAST SECTOR
FORM47 JSR WRTTRK
 TST DBSDF ONE SIDE?
 BEQ FORM6
 TST SIDE
 BNE FORM6
 INC SIDE
 BRA FORM32

FORM6 INC TRACK
 LDAA TRACK
 CMPA #MAXTRK
 BNE FORM7 REPEAT UNTIL LAST TRACK
 JMP SETUP DONE...GO FINISH UP

FORM7 STAA TRACK
 CLR SIDE
 BRA FORM32

* EXIT ROUTINES

EXIT LDX #ABORTS
EXIT2 JSR PSTRNG
 JMP WARMST
EXIT4 LDX #WPST WRITE PROTECTED
 BRA EXIT2

* PROCESS SECTOR IN RAM

DOSEC LDAA TRACK
 LDAB SECTOR
 STX INDEX1 SAVE INDEX
 LDX #SSMAP5 POINT TO CORRECT MAP
 BSR ADDXB POINT TO SECTOR NUMBER
 LDAB 0,X GET SECTOR NUMBER
 LDX INDEX1 RESTOR INDEX
DOSEC2 INCB
 TST DBSDF
 BNE DOSEC3 BR DOUBLE SIDED
 CMPB #MAXS0+1 END OF TRACK
 BRA DOSEC4
DOSEC3 CMPB #MAXS1+1 END OF TRACK
DOSEC4 BNE DOSEC7 BR IF NOT
 INCA INC TRACK NUMBER
 LDAB #1 RESET SECTOR NUMBER
 CMPA #MAXTRK END OF DISK
 BNE DOSEC7 BR IF NOT
 CLRA SET ZERO FORWARD LINK
 CLRB

DOSEC7 STAA 0,X FORWARD LINK
 STAB 1,X
 LDAB #128
 BSR ADDXB ADD 128 TO INDEX
 LDAB #128 ADD ANOTHER 128 TO INDEX

* ADD ACCB TO INDEX
ADDXB STX INDEX3
 ADDB INDEX3+1
 STAB INDEX3+1
 BCC ADDXB9
 INC INDEX3
ADDXB9 LDX INDEX3
 RTS

SSMAP5 FCB 1,3,5,7,9,2,4,6,8,10
       FCB 11,13,15,17,19,12,14,16,18,20

*************************************************
* DISK TESTING AND TABLE SETUP

* Read all sectors for errors

SETUP TST DBSDF
 BNE SETU01 BR IF DOUBLE SIDED
 LDX #TOTSS TOTAL SECTORS
 STX SECCNT SAVE IT
 LDX #LASTSS
 BRA SETU02

SETU01 LDX #TOTDS TOTAL SECTORS
 STX SECCNT
 LDX #LASTDS

SETU02 STX LSTAVL
 LDX #FIRST SET FIRST AVAIL
 STX FSTAVL
 LDAA DRN DRIVE NUMBER
 STAA WORK+3
 CLRA 
 STAA BADCNT
 STAA TRACK SET TRACK 0
 STAA SECTOR SET SECTOR 0
SETUP2 BSR CHKSEC GO CHECK SECTOR
 BNE REMSEC ERRORS?
 CLR BADCNT CLEAR COUNT

SETUP4 LDAA TRACK
 LDAB SECTOR
 BSR FIXSEC GET NEXT ADR
 BNE SETUP5
 JMP DOTRK BR IF FINISHED

SETUP5 STAA TRACK
 STAB SECTOR
 BRA SETUP2

* CHECK IF SECTOR GOOD

CHKSEC LDX #WORK POINT TO FCB
 LDAA TRACK
 STAA FCS,X SET CURRENT TRK
 LDAA SECTOR
 STAA FCS+1,X SET CURRENT TRK
 JMP READSS

* SET TRACK & SECTOR TO NEXT

FIXSEC INCB
 TSTA 
 BNE FIXSE1
 CMPB #1
 BNE FIXSE1
 INCB 
FIXSE1 TST DBSDF
 BNE FIXSE2 BR IF DOUBLE SIDED
 CMPB #MAXS0+1 END OF SIDE 0
 BRA FIXSE3
FIXSE2 CMPB #MAXS1+1 END OF SIDE 1
FIXSE3 BNE FIXSE4
 INCA  NEXT TRACK
 LDAB #1 SECTOR NUMBER 1
 CMPA #MAXTRK END OF DISK
FIXSE4 RTS

* REMOVE BAD SECTOR FROM FREE SECTOR CHAIN

REMSEC INC BADCNT UPDATE COUNTER
 BEQ REMSE1 OVERFLOW?
 LDAA TRACK
 BNE REMSE2 TRACK 0?
 LDAB SECTOR
 CMPB #DIRSEC PAST DIRECTORY?
 BHI REMSE2
REMSE1 LDX #FATERS REPORT FATAL ERROR
 JMP EXIT2

REMSE2 LDX #WORK POINT TO FCB
 LDAA FSTAVL GET 1ST TRACK
 LDAB FSTAVL+1 AND SECTOR
 CMPA TRACK CHECK TRACK
 BNE REMSE3
 CMPB SECTOR
 BNE REMSE3
 BSR FIXSEC SET TO NEXT
 STAA FSTAVL
 STAB FSTAVL+1
 BRA REMSE8

REMSE3 LDAA TRACK
 LDAB SECTOR
 SUBB BADCNT
 BEQ REMS35 UNDERFLOW?
 BPL REMSE4

REMS35 DECA DEC TRACK
 TST DBSDF
 BNE REMS36
 LDAB #MAXS0 MAX SIDE 0
 BRA REMSE4
REMS36 LDAB #MAXS1 SIDE 1

REMSE4 STAA FCS,X SET CURRENT ADR
 STAB FCS+1,X
 BSR READSS GO DO READ
 BNE REMSE1 ERROR?
 LDAA FSB,X GET LINK ADR
 LDAB FSB+1,X
 BSR FIXSEC POINT TO NEXT
 BNE REMSE6 OVERFLOW?
 LDAA FCS,X GET CURRENT ADDRESS
 LDAB FCS+1,X
 STAA LSTAVL SET NEW LAST AVAIL
 STAB LSTAVL+1
 CLRA  SET END LINK
 CLRB
REMSE6 STAA FSB,X SET NEW LINK
 STAB FSB+1,X
 BSR WRITSS GO DO WRITE
 BNE REMSE1
REMSE8 LDX SECCNT GET SEC COUNT
 DEX SUBTRACT ONE SECTOR
 STX SECCNT SAVE NEW COUNT
 LDX #BADSS REPORT BAD SECTOR
 JSR PSTRNG OUTPUT IT
 LDX #TRACK POINT TO ADDRESS
 JSR OUTHEX
 LDAA #'  SPACE
 JSR PUTCHR
 INX POINT TO SECTOR
 JSR OUTHEX
 JMP SETUP4 CONTINUE

* READ A SECTOR

READSS LDX #WORK POINT TO FCB
 LDAA #RDSS SET UP COMMAND
 STAA 0,X
 JMP FMSCAL GO DO IT

* WRITE A SECTOR

WRITSS LDX #WORK POINT TO FCB
 LDAA #WTSS
 STAA 0,X
 JSR FMSCAL GO DO IT
 BEQ READSS ERRORS?
 RTS ERROR RETURN

* SETUP SYSTEM INFORMATION RECORD

DOTRK LDX #WORK
 CLR FCS,X SET TO DIS
 LDAA #3 SECTOR 3
 STAA FCS+1,X
 JSR READSS READ IN SIR SECTION
 BNE DOTRK4 ERROR?
 LDX #WORK FIX POINTER
 CLR FSB,X CLEAR FOWARD LINK
 CLR FSB+1,X
 LDAA FSTAVL ADDR OF 1ST FREE SECTOR
 LDAB FSTAVL+1
 STAA AVLP,X SET IN SIR
 STAB AVLP+1,X
 LDAA LSTAVL ADDR OF LAST FREE SECTOR
 LDAB LSTAVL+1
 STAA AVLP+2,X PUT IN SIR
 STAB AVLP+3,X
 LDAA SECCNT GET TOTAL SECTORS
 LDAB SECCNT+1
 STAA AVLP+4,X
 STAB AVLP+5,X
 TST DBSDF
 BNE DOTR21
 LDAA #MAXS0 MAX SINGLE SIDED
 BRA DOTR22
DOTR21 LDAA #MAXS1 MAX DOUBLE SIDED
DOTR22 STAA AVLP+10,X
 LDAA #MAXTRK-1
 STAA AVLP+9,X
 LDAA SMONTH
 LDAB SDAYMN
 STAA AVLP+6,X
 STAB AVLP+7,X
 LDAA SYEARN
 STAA AVLP+8,X

 LDAB #13 LENGHT OF NAME & NUMBER
 LDX #VOLNAM POINT TO VOLUME NAME
 STX INDEX2 SAVE INDEX
 LDX #WORK
DOTR33 STX INDEX1 SAVE INDEX
 LDX INDEX2
 LDAA 0,X
 INX 
 STX INDEX2
 LDX INDEX1
 STAA FSB+IRS,X
 INX
 DECB
 BNE DOTR33

 JSR WRITSS WRITE SIR BACK OUT
 BEQ DIRINT
DOTRK4 JMP REMSE1 GO REPORT ERROR

* INITIALIZE DIRECTORY

DIRINT LDX #WORK
 TST DBSDF
 BNE DIRIN1 BR IF DOUBLE SIDED
 LDAA #MAXS0 MAX SECTORS
 BRA DIRIN2
DIRIN1 LDAA #MAXS1 MAX SECTORS DOUBLE SIDED
DIRIN2 STAA FCS+1,X
 JSR READSS READ IN SECTOR
 BNE DOTRK4 ERRORS?
 LDX #WORK RESTORE POINTER
 CLR FSB,X CLEAR LINK
 CLR FSB+1,X
 JSR WRITSS WRITE SECTOR BACK
 BNE DOTRK4 ERRORS?

* SAVE BOOT ON TRACK 0 SECTOR 0

DOBOOT LDX #flxBoot POINT TO LOADER
 CLRA TRACK #0
 CLRB SECTOR #0
 JSR DWRITE WRITE THE SECTOR
 BNE DOTRK4 ERRORS?

* REPORT TOTAL SECTORS AND EXIT

 LDX #WORK SETUP AN FCB
 LDAA #16 OPEN SIR FUNCTION
 STAA 0,X
 JSR FMSCAL OPEN SIR
 BNE DOTRK4
 LDAA #7 GET INFO RECORD FUNCTION
 STAA 0,X
 JSR FMSCAL GET 1ST INFO RECORD
 BNE DOTRK4
 LDX #CMPLTE FORMATTING COMPLETE
 JSR PSTRNG REPORT IT
 LDX #WORK+21 TOTAL IS IN INFO RECORD
 CLRB
 JSR OUTDEC
 JMP WARMST ALL FINISHED!

**************************************************
* WRITE TRACK ROUTINE
* FOR PERCOM LFD-400

WRTTRK LDX #WORK POINT TO DATA
 STX INDEX1
 CLR SECTOR

WTLOOP LDX #SSMAP5 PHYS TO LOGICAL MAP
 LDAA SECTOR A=PHYSICAL SECTOR
 STAA *+4 MODIFY FOLLOWING INDEX OFFSET
 LDAB 0,X B=LOGICAL SECTOR

 ADDA #WORK/256 A=MSB OF SECTOR ADDRESS
 STAA INDEX1
 LDX INDEX1 X->SECTOR DATA

 LDAA TRACK 
 JSR DWRITE
 BNE WTERROR

 LDAA SECTOR
 ADDA #2
 STAA SECTOR

 CMPA #MAXS0 PAST LAST SECTOR?
 BCS WTLOOP

 SUBA #MAXS0+1 10->$FF, 11->0
 ANDA #1 10->1, 11->0
 STAA SECTOR
 BNE WTLOOP

 RTS

WTERROR JMP EXIT

* STRINGS
SURES FCC "ARE YOU SURE? "
 FCB $04
WPST FCC "DISK IS PROTECTED!"
 FCB $04
SCRDS FCC "SCRATCH DISK IN DRIVE "
 FCB $04
FATERS FCC "FATAL ERROR --- "
ABORTS FCC "FORMATTING ABORTED"
 FCB $04
BADSS FCC "BAD SECTOR AT "
 FCB $04
CMPLTE FCC "FORMATTING COMPLETE"
 FCB $0D,$0A,$00,$00,$00
 FCC "TOTAL SECTORS = "
 FCB $04
DBST FCC "DOUBLE SIDED DISK? "
 FCB $04
NMSTR FCC "VOLUME NAME? "
 FCB $04
NUMSTR FCC "VOLUME NUMBER? "
 FCB $04

*------------------------------------------------------------------
*  FLEXLOAD.ASM
*      Flex 2.0 loader for Percom LFD-400 controller
*
*      Mike Douglas, 03/04/2020
*------------------------------------------------------------------
BOOTLOC	equ	$2400		;Flex boot loader runs here
RDSEC	equ	$C00C		;read a sector (MiniDOS EPROM)
WTSEC	equ	$C00F		;write a sector (MiniDOS EPROM)

* Page 0 data maintained by MiniDOS

	org	0
drvNum	rmb	1		;drive number in MS 2 bits
trk	rmb	1		;desired track
sctr	rmb	1		;desired sector

bakLnk	rmb	2		;file backward link
fwdLnk	rmb	2		;file forward link
bytCnt	rmb	1		;sector byte count
addres	rmb	2		;data address vector
filTyp	rmb	1		;file type code	
ckSum	rmb	2		;sector checksum
postAm	rmb	2		;post amble

crnTrk	rmb	1		;current track
trkTbl	rmb	4		;track each drive is on
wrtAddr	rmb	2		;write buffer address
rdAddr	rmb	2		;read buffer address

*------------------------------------------------------------------
* Boot ROM jumps here after loading this from sector 0
*------------------------------------------------------------------
	org	BOOTLOC		;boot ROM puts this program here

flxBoot	lds	#SSTACK		;init stack pointer
	bra	loadFlx		;go load Flex

flexTrk	fcb	1		;track for FLEX2.SYS
flexSec	fcb	10		;sector for find FLEX2.SYS
			
pFlex	rmb	2		;pointer to Flex entry address
pDest	rmb	2		;pointer to destination in memory
pSource	rmb	2		;pointer to data in secBuf

*------------------------------------------------------------------
* loadFlx - Entry point for loading Flex from disk. The drive
*    that loaded this program is used to load Flex. This allows
*    booting from any drive.
*------------------------------------------------------------------
loadFlx	bsr	read1st		;read first sector of Flex

load1	bsr	getByte		;get next byte

	cmpa	#$02		;data record header?
	beq	load2

	cmpa	#$16		;transfer address header?
	bne	load1		;loop if neither

	bsr	getByte		;get transfer address
	staa	pFlex		;MSB
	bsr	getByte		;LSB
	staa	pFlex+1

	ldx	pFlex		;jump to Flex
	jmp	0,x

load2	bsr	getByte		;A=load address MSB
	psha
	bsr	getByte		;A=load address LSB
	pulb			;B=load address MSB

	staa	pDest+1		;save load address LSB
	stab	pDest		;MSB

	bsr	getByte		;A=byte count
	tab			;B=byte count
	beq	load1		;byte count was zero

load3	pshb
	bsr	getByte		;get next data byte
	pulb

	ldx	pDest		;X->where to put the data
	staa	0,x
	inx
	stx	pDest

	decb
	bne	load3		;loop for byte count in B

	bra	load1		;get next record

*------------------------------------------------------------------
* readSec 
*------------------------------------------------------------------
read1st	ldaa	flexTrk		;read 1st sector of Flex
	ldab	flexSec

readSec	staa	trk		;give track to MiniDOS

	ldx	#skewTbl-1	;X->sector skew table w/1-index
	stab	*+4		;modify the following index offset
	ldab	0,x		;B=physical sector
	stab	sctr		;give sector to MiniDOS

	ldx	#secBuf		;X->secBuf
	stx	rdAddr		;give buffer address to MiniDOS

	clr	bytCnt		;read 256 bytes

	jsr	RDSEC		;read sector in MiniDOS
	bcs	flxBoot		;error, start over

	ldx	#secBuf+4	;data starts at offset 4
	stx	pSource		;init source pointer

	rts

* skewTbl maps logical sectors 1-10 to physical sectors 0-9 with
*    a skew of 5.

skewTbl	fcb	0,5,1,6,2,7,3,8,4,9

*------------------------------------------------------------------
* getByte - Get next byte from sector buffer. Retrieve next
*    sector as needed.
*------------------------------------------------------------------
getByte	ldx	pSource		;X->next byte 
	cpx	#secBuf+256	;reached end of sector buffer?
	beq	nextSec		;yes, get the next sector

	ldaa	0,x		;otherwise, return the next byte
	inx
	stx	pSource		;save updated pointer
	rts

nextSec	ldaa	secBuf		;A=next track
	ldab	secBuf+1	;B=next sector
	bsr	readSec
	bra	getByte

* Sector buffer starts here

secBuf	equ	*

	end
