; ********************** APD loader variables *************************
#set Max_Track_Count   = 166			; max tracks on an APD disc
#set Max_Sector_Count  = Max_Track_Count * 16	; max sectors - a guess
#set APD_Track_Buffer  = (Max_Track_Count * 4) + (Max_Sector_Count * 8)
#set Max_APD_File_Size = (928 * 1024) - APD_Track_Buffer	; memory allocated
#set R_buffer          = 12			; registers
#set R_sectorinfo      = 11
#set R_bitsleft        = 10
#set R_nextbit         = 9
#set R_curbit          = 8
#set R_bitrot          = 7
#set R_sectorsize      = 6
#set R_syncmark        = 5





.Entry_ADFMount_APD			;read APD
 STR     R14, [R13, #-4]!
					;preallocate memory, hope we have enough
					;hardcoded disc size for time being
 MOV     R4, #Max_APD_File_Size + APD_Track_Buffer
 BL      MemAlloc			;Allocate memory
 MOVVS   R2, #0				;if an error occurred, zero address
 MOVVS   R4, #0

 LDRVC   R2, DA_address			;increase start of buffer
 MOVVC   R3, #APD_Track_Buffer
 ADDVC   R1, R2, R3			;by size of APD track buffer
 STRVC   R1, ADF_Buffer_Address
 ADDVC   R4, R2, #Max_Track_Count * 4
 STR     R2, APD_Tracks
 STR     R4, APD_Sectors
 LDRVS   PC, [R13], #4			;exit on error

 MVN     R0, #0				;clear the track and sector table
 ._L1
   STR     R0, [R2], #4
   SUBS    R3, R3, #4
 BNE     _L1

 LDR     R0, GZ_File_Handle		;file handle
 MOV     R1, #0
 MOV     R2, #0
 SWI     XZLib_GZSeek			;go back to beginning of file

 BL      APD_Read_File

 ADR     R1, JFD_tmp			;buffer address
 LDR     R2, DA_address
 LDR     R3, APD_Tracks
 SUB     R0, R3, R2			;offset to Track table
 ADD     R0, R0, #JFD_Header ;+ 4
 STR     R0, [R1, #JFD_Track_Table]
 LDR     R3, APD_Sectors
 SUB     R0, R3, R2
 ADD     R0, R0, #JFD_Header ;+ 4
 STR     R0, [R1, #JFD_Sector_Table]	;offset to Sector table
 MOV     R0, #APD_Track_Buffer
 ADD     R0, R0, #JFD_Header ;+ 4
 STR     R0, [R1, #JFD_Data]		;offset to data
 LDR     R0, DA_size
 STR     R0, [R1, #JFD_Size]		;memory required to load

 MOV     R2, #2
 STR     R2, ADF_Mounted		;inform DiscOp code its an APD
 STR     R2, ADF_Changed		;inform FileCore the disc has changed

 MOV     R0, #0				;no error
 ADD     R13, R13, #4			;clear stack
B       Entry_ADFMount_mounted




;APD_Read_File
;-------------
;Read APD file read only
;
;Entry:
; R0 - pointer to filename

.APD_Read_File
 STMFD   R13!, {R1-R5, R11, R14}

 MOV     R0, #Module_Claim		;claim space for APD header
 MOV     R3, #8 + (166*12)		;amount to claim
 SWI     XOS_Module			;PRM1-237
;### needs error code
 LDMVSFD R13!, {R1-R5, R11, PC}
 STR     R2, APD_Temp_Header		;store address

 LDR     R0, GZ_File_Handle		;zlib file handle
 MOV     R1, R2				;buffer address
 MOV     R2, R3				;bytes to read
 SWI     XZLib_GZRead			;read the APD header
;### needs error code
 LDMVSFD R13!, {R1-R5, R11, PC}

 MOV     R0, #0
 STR     R0, APD_Temp_Header_Pos	;position in header file

 LDR     R_buffer, ADF_Buffer_Address	;address we're writing too
 LDR     R_sectorinfo, APD_Sectors	;sector table

 BL      APD_Read_Word			;read APDX string
 BL      APD_Read_Word			;read APD version
;### validate its okay

 MOV     R2, #8 + (166*12)		;start of track data
 MOV     R5, #0				;tracks counter
 MOV     R4, #8				;position of track length being read
 ._L1
   LDR     R0, prevent_Hourglass
   TEQ     R0, #0			;should we display an Hourglass?
   MOVEQ   R0, R5, LSR #1		;YES
   ADDEQ   R0, R0, R5, LSR #3		; |  R0 = 100/160 * R5
   SWIEQ   XHourglass_Percentage	; |+ display an hourglass PRM2-752

   LDR     R0, APD_Tracks		;pointer to track table
   LDR     R14, APD_Sectors		;sector table
   SUB     R14, R_sectorinfo, R14	;ptr to start of track in sector table
   STR     R14, [R0, R5, LSL #2]	;store track start pointer


					;*****************************
   MOV     R0, R4			;SD track info pointer
   BL      APD_Read_Word_ABS		;read track length
   ADD     R4, R4, #4			;increase track info pointer
   MOVS    R_bitsleft, R0
   BEQ     _SD_Unformatted		;if length is 0, its unformatted

   ADD     R0, R0, #7
   MOV     R0, R0, LSR #3		;size of track data in bytes
   BL      APD_Read_Track
   ADD     R2, R2, R0			;increase file pointer

   MOV     R1, #1			;FileCore for SD
   BL      APD_decodeFM			;decode FM data
   ._SD_Unformatted
					;*****************************

					;*****************************
   MOV     R0, R4			;DD track info pointer
   BL      APD_Read_Word_ABS		;read track length
   ADD     R4, R4, #4			;increase track info pointer
   MOVS    R_bitsleft, R0
   BEQ     _DD_Unformatted		;if length is 0, its unformatted

   ADD     R0, R0, #7
   MOV     R0, R0, LSR #3		;size of track data in bytes
   BL      APD_Read_Track
   ADD     R2, R2, R0			;increase file pointer

   MOV     R1, #2			;FileCore for DD
   BL      APD_decodeMFM		;decode MFM data
   ._DD_Unformatted
					;*****************************

					;*****************************
   MOV     R0, R4			;QD track info pointer
   BL      APD_Read_Word_ABS		;read track length
   ADD     R4, R4, #4			;increase track info pointer
   MOVS    R_bitsleft, R0
   BEQ     _QD_Unformatted		;if length is 0, its unformatted

   ADD     R0, R0, #7
   MOV     R0, R0, LSR #3		;size of track data in bytes
   BL      APD_Read_Track
   ADD     R2, R2, R0			;increase file pointer

   MOV     R1, #4			;FileCore for QD
   BL      APD_decodeMFM		;decode MFM data
   ._QD_Unformatted
					;*****************************

   LDR     R0, APD_Sectors		;sector table
   SUB     R14, R_sectorinfo, R0	;get offset within table
   LDR     R0, APD_Tracks		;track table
   LDR     R1, [R0, R5, LSL #2]		;load sector pointer of current track
   SUBS    R14, R14, R1			;did we find any sectors?
   MVN     R14, #0
   STREQ   R14, [R0, R5, LSL #2]	;NO, mark track as unformatted
   STRNE   R14, [R_sectorinfo], #4	;YES, terminate sector info
					;.. for this track

   ADD     R5, R5, #1			;increase track counter
   TEQ     R5, #Max_Track_Count
 BNE     _L1

 LDR     R0, DA_address
 SUB     R0, R_buffer, R0		;work out new DA size
 BL      Reduce_DynamicArea		;hand back any unused memory

 LDR     R2, APD_Temp_Track		;temp buffer address
 TEQ     R2, #0				;did we allocate any
 MOVNE   R0, #0
 STRNE   R0, APD_Temp_Track		;clear pointer
 STRNE   R0, APD_Temp_Track_Length
 MOVNE   R0, #Module_Free		;yes, free it
 SWINE   XOS_Module			;PRM1-238

 LDR     R2, APD_Temp_Header		;temp buffer address
 TEQ     R2, #0				;did we allocate any
 MOVNE   R0, #0
 STRNE   R0, APD_Temp_Header		;clear pointer
 MOVNE   R0, #Module_Free		;free APD header
 SWINE   XOS_Module			;PRM1-238
LDMFD   R13!, {R1-R5, R11, PC}





;APD_Read_Track
;--------------
;Read one track into memory and pre-read the first two words
;
;Entry:
; R2 - file position pointer
; R0 - number of bytes to read
;
;Exit:
; R_curbit  - 1st word of track
; R_nextbit - 2nd word of track
; R_bitrot  - 32

.APD_Read_Track
 STMFD   R13!, {R0-R4, R12, R14}
 ADR     R12, VARS

 MOV     R3, R0				;bytes to read
 MOV     R4, R2				;file position pointer
 LDR     R2, [R12, #APD_Temp_Track - VARS]	;temp buffer address
 LDR     R1, [R12, #APD_Temp_Track_Length - VARS]	;see if our temp buffer is big enough
 CMP     R1, R0
 BHS     _Track_allocated

 MOV     R0, #Module_Free		;release current allocation
 SWI     XOS_Module			;PRM1-238
 MOV     R0, #0
 STR     R0, [R12, #APD_Temp_Track - VARS]	;clear pointer
 STR     R0, [R12, #APD_Temp_Track_Length - VARS]

 MOV     R0, #Module_Claim		;claim more space
 SWI     XOS_Module			;PRM1-237
;### needs error code
 STRVC   R2, [R12, #APD_Temp_Track - VARS]	;store address
 STRVC   R3, [R12, #APD_Temp_Track_Length - VARS]	;store size

 ._Track_allocated
 STR     R2, [R12, #APD_File_Position - VARS]	;store file position pointer
					;R2 is memory address
					;R3 is now size

 LDR     R0, [R12, #GZ_File_Handle - VARS]	;zlib file handle
 MOV     R1, R4				;position in decompressed data
 MOV     R2, #0				;read absolute
 SWI     XZLib_GZSeek			;go to the start of the track
;### needs error code

 LDR     R0, [R12, #GZ_File_Handle - VARS]	;zlib file handle
 LDR     R1, [R12, #APD_Temp_Track - VARS]	;buffer
 MOV     R2, R3				;bytes to read
 SWI     XZLib_GZRead			;read the track in
;### needs error code

 LDR     R2, [R12, #APD_File_Position - VARS]	;position in track
 LDR     R_curbit, [R2], #4		;load the first word
 LDR     R_nextbit, [R2], #4		;load the next word
 STR     R2, [R12, #APD_File_Position - VARS]	;store updated pointer back

 EOR     R0, R_curbit, R_curbit, ROR #16	;convert from little endian
 BIC     R0, R0, #&00FF0000
 MOV     R_curbit, R_curbit, ROR #8
 EOR     R_curbit, R_curbit, R0, LSR #8

 EOR     R0, R_nextbit, R_nextbit, ROR #16
 BIC     R0, R0, #&00FF0000
 MOV     R_nextbit, R_nextbit, ROR #8
 EOR     R_nextbit, R_nextbit, R0, LSR #8

 MOV     R_bitrot, #32			;bits remaining in next word
LDMFD   R13!, {R0-R4, R12, PC}





;APD_Read_Word_ABS
;-----------------
;Read one 32 bit word from file at an absolute address
;
;Entry:
; R0 - position pointer
;
;Exit:
; R0 - word

.APD_Read_Word_ABS
 STMFD   R13!, {R1, R14}
 ADR     R14, VARS

 ADD     R1, R0, #4			;update position pointer
 STR     R1, [R14, #APD_Temp_Header_Pos - VARS]

 LDR     R1, [R14, #APD_Temp_Header - VARS]	;address of buffer
 LDR     R0, [R1, R0]			;load word
LDMFD   R13!, {R1, PC}




;APD_Read_Word
;-------------
;Read one 32 bit word from file
;
;Exit:
; R0 - word

.APD_Read_Word
 STMFD   R13!, {R1, R14}
 ADR     R14, VARS

 LDR     R0, [R14, #APD_Temp_Header_Pos - VARS]	;get current position pointer
 ADD     R1, R0, #4			;update position pointer
 STR     R1, [R14, #APD_Temp_Header_Pos - VARS]

 LDR     R1, [R14, #APD_Temp_Header - VARS]	;address of buffer
 LDR     R0, [R1, R0]			;load word

LDMFD   R13!, {R1, PC}




;APD_decodeMFM
;-------------
;Decode one track into raw data and store sectors in sector table
;
;Entry:
; R1 - density (1-SD, 2-DD, 4-QD, 8-OD)
;
;Exit:
; R1 - corrupt

.APD_decodeMFM
 ADR     R0, VARS

 STR     R1, [R0, #current_density - VARS]	;store the density we're processing

 MOV     R1, #&A1			;converted 4489
 STR     R1, [R0, #SiS_syncmark - VARS]	;..used for nested sectors

 MOV     R1,     #&44000000		;44894489 / A1 A1
 ORR     R1, R1, #&00890000
 ORR     R1, R1, R1, LSR #16
 STR     R1, [R0, #bit_sync_mark - VARS]	;sync to this within bitstream

 MOV     R1, R1, LSL #16		;44895554 / A1 FE
 ORR     R1, R1, #&5500
 ORR     R1, R1, #&0054
 STR     R1, [R0, #sec_sync_mark - VARS]	;MFM sector mark used in nested check

 BIC     R1, R1, #&FF000000		;5554 / FE
 BIC     R1, R1, #&00FF0000
 STR     R1, [R0, #mfm5554 - VARS]	;sector ID mark

 MOV     R1,     #&5500			;5545 / FB
 ORR     R1, R1, #&0045
 STR     R1, [R0, #mfm5545 - VARS]	;MFM data markr
B       APD_decode_track




;APD_decodeFM
;-------------
;Decode one track into raw data and store sectors in sector table
;
;Entry:
; R1 - density (1-SD, 2-DD, 4-QD, 8-OD)
;
;Exit:
; R1 - corrupt

.APD_decodeFM
 ADR     R0, VARS

 STR     R1, [R0, #current_density - VARS]	;store the density we're processing

 MOV     R1, #&00			;converted AAAA
 STR     R1, [R0, #SiS_syncmark - VARS]		;..used for nested sectors

 MOV     R1,     #&FF000000		;FFFFAAAA / FF 00
 ORR     R1, R1, #&0000AA00
 ORR     R1, R1, R1, LSR #8
 STR     R1, [R0, #bit_sync_mark - VARS]	;sync to this within bitstream

 MOV     R1, R1, LSL #16
 ORR     R1, R1, #&0000F500		;AAAAF57E / 00 FE
 ORR     R1, R1, #&0000007E
 STR     R1, [R0, #sec_sync_mark - VARS]	;FM sector mark used in nested check

 MOV     R1,     #&F500			;F57E / FE
 ORR     R1, R1, #&007E
 STR     R1, [R0, #mfm5554 - VARS]	;sector ID mark

 MOV     R1,     #&F500			;F56F / FB
 ORR     R1, R1, #&006F
 STR     R1, [R0, #mfm5545 - VARS]	;FM data mark
B       APD_decode_track




;APD_decode_track
;----------------
;Decode one track into raw data and store sectors in sector table

.APD_decode_track
 STMFD   R13!, {R0, R2-R5, R14}

 LDR     R0, ADF_Buffer_Address		;check we're not about to run
 SUB     R0, R_buffer, R0		;..out of buffer
 SUB     R0, R0, #Max_APD_File_Size	;currently 900kb
 ADDS    R0, R0, #5 * 1024		;allow fill to size - 5K
 LDMPLFD R13!, {R0, R2-R5, PC}		;too close to buffer limit, exit

 MOV     R0, R_bitsleft			;need to calculate sector timing divisor
 MOV     R2, #Track_Length_MS << 16	;one track rotation in ms
 M_DIV   R2, R0, R3			;R2 = 200/track length in bits
 STR     R2, sector_timing

 .APD_decode_track_L1
   B       APD_decodexFM_find_sector
   .decodeMFM_exit
   ;------------------------------------	;sector within sector
   ADR     R2, SiS
   LDR     R0, [R2], #4
   CMN     R0, #1				;did we find any?
   STRNE   R0, APD_File_Position		;YES, deal with sector
   LDMNEIA R2!, {R_bitrot, R_nextbit, R_bitsleft}	;|    jump back in data
   LDRNE   R_curbit, bit_sync_mark		;|    reset R_cutbit
						;|    .. to correct the CRC
   BNE     decodeMFM_sector_found		;|+   and decode the sector
   ;------------------------------------

   CMP     R_bitsleft, #0
 BPL     APD_decode_track_L1			;loop until we run out of data

LDMFD   R13!, {R0, R2-R5, PC}




;APD_decodexFM_find_sector
;-------------------------
;Decodes one sector of FM / MFM

.APD_decodexFM_find_sector
 BL      MFM_find_sync

.decodeMFM_sector_found
 MVN     R0, #0
 ;------------------------------------	;sector within sector
 STR     R0, SiS
 ;------------------------------------
 MOV     R0, R0, LSR #16		;reset CRC to FFFF
 STR     R0, MFM_crc

 LDR     R_syncmark, mfm5554		;look for ID mark
 BL      MFM_find_ID

 LDR     R0, current_density
 TEQ     R0, #1				;are we processing FM?
 MVNEQ   R0, #0				;YES
 MOVEQ   R0, R0, LSR #16		;...reset CRC to FFFF
 STREQ   R0, MFM_crc

 MOV     R0, #16			;calc CRC on ID mark
 SUBS    R_bitsleft, R_bitsleft, R0	;reduce bit counter
 BMI     decodeMFM_exit			;exit if we run out of data
 BL      read_MFM			;read next byte
 MOV     R0, #16			;calc CRC on track no.
 SUBS    R_bitsleft, R_bitsleft, R0	;reduce bit counter
 BMI     decodeMFM_exit			;exit if we run out of data
 BL      read_MFM			;read next byte
 MOV     R0, #16			;calc CRC on head
 SUBS    R_bitsleft, R_bitsleft, R0	;reduce bit counter
 BMI     decodeMFM_exit			;exit if we run out of data
 BL      read_MFM			;read next byte

 MOV     R0, R_curbit
 BL      oddbits			;R0 = <NUL><NUL><sector no.><sector size>

 STR     R0, [R13, #-4]!		;preserve R0
 MOV     R0, #16			;calc CRC on sector no
 SUBS    R_bitsleft, R_bitsleft, R0	;reduce bit counter
 BMI     decodeMFM_exit			;exit if we run out of data
 BL      read_MFM			;read next byte

 MOV     R0, #16			;calc CRC on sector size
 SUBS    R_bitsleft, R_bitsleft, R0	;reduce bit counter
 BMI     decodeMFM_exit			;exit if we run out of data
 BL      read_MFM			;read next byte

 MOV     R0, R_curbit
 BL      oddbits
 MOV     R1, R0				;R1 = sector ID CRC

 LDR     R0, sector_timing		;calculate time in ms from start of track
 MUL     R14, R0, R_bitsleft
 MOV     R14, R14, LSR #16		;shift back down to correct value
 RSB     R14, R14, #Track_Length_MS	;R14 = 200 - (200/track length in bits)
 AND     R14, R14, #&FF			;just in case it overflows
 LDR     R0, MFM_crc
 EORS    R1, R1, R0			;is the CRC ok?
 LDR     R0, [R13], #4			;| restore R0
 LDR     R1, current_density		;| get the current density and append it
 ORR     R0, R0, R1, LSL #16		;| R0=<NUL><density><sec no.><sec size>
 BIC     R0, R0, #bits_crc		;| clear CRC bits, in case sec size>15
 ORRNE   R0, R0, #bit_ID_CRC		;| set ID CRC flag if CRC error
 ORREQ   R0, R0, #bit_sector_CRC	;| assume the CRC is wrong on data
 ORR     R0, R0, R14, LSL #24		;| append sector time
 STR     R0, [R_sectorinfo], #4		;| store sector ID
 LDR     R14, ADF_Buffer_Address	;| memory buffer
 SUB     R14, R_buffer, R14		;| pointer to start of track in sec table
 STR     R14, [R_sectorinfo], #4	;| store sector buffer offset
 BNE     decodeMFM_exit			;|+ NO, ignore sector

 AND     R0, R0, #%11			;mask to ensure its capped at 1024
 ADD     R0, R0, #7			;sector size = 1 << (R0 + 7)
 MOV     R_sectorsize, #1
 MOV     R_sectorsize, R_sectorsize, LSL R0

 BL      MFM_find_sync

 MVN     R0, #0
 MOV     R0, R0, LSR #16		;reset CRC to FFFF
 STR     R0, MFM_crc

 LDR     R_syncmark, mfm5545		;look for data mark
 BL      MFM_find_ID

 LDR     R0, current_density
 TEQ     R0, #1				;are we processing FM?
 MVNEQ   R0, #0				;YES
 MOVEQ   R0, R0, LSR #16		;...reset CRC to FFFF
 STREQ   R0, MFM_crc

 MOV     R0, #16			;read next byte
 SUBS    R_bitsleft, R_bitsleft, R0	;reduce bit counter
 BMI     _shortSector			;exit if we run out of data
 BL      read_MFM			;read next byte

 LDR     R_syncmark, bit_sync_mark	;used to check for sector within sector

 ._L1
   MOV     R0, R_curbit			;decode a byte
   BL      oddbits			;convert MFM to data

   MOV     R0, R0, LSR #8		;...and store first byte
   STRB    R0, [R_buffer], #1

   MOV     R0, #16			;read next byte
   SUBS    R_bitsleft, R_bitsleft, R0	;reduce bit counter
   BMI     decodeMFM_exit		;exit if we run out of data
   BL      read_MFM

   ;------------------------------------;sector within sector
   TEQ     R_curbit, R_syncmark
   BNE     _byte_okay

   ADR     R2, SiS			;check if we've already found
   LDR     R0, [R2]			;..a nested sector
   CMN     R0, #1			;..no need to store any more
   BNE     _byte_okay			;..as they'll be captured later

   STMFD   R13!, {R_syncmark}		;store the sync mark
   MOV     R0, R_syncmark, LSL #16	;..we now need to remove duplicated
   ORR     R_syncmark, R0, R0, LSR #16	;..of the 2nd word

   LDR     R0, APD_File_Position	;get the current position
   STMIA   R2, {R0, R_bitrot, R_nextbit, R_bitsleft}
   ._capture_sync_marks
     LDR     R0, SiS_syncmark		;store the sync mark in the data
     STRB    R0, [R_buffer], #1

     MOV     R0, #16			;read next byte
     SUBS    R_bitsleft, R_bitsleft, R0	;reduce bit counter
     LDMMIFD R13!, {R_syncmark}		;clear stack if we're out of data
     BMI     _shortSector		;..and exit
     BL      read_MFM

     SUBS    R_sectorsize, R_sectorsize, #1	;reduce sectorsize counter
     BEQ     _premature_sector_end

     TEQ     R_curbit, R_syncmark	;skip over additional syncs
   BEQ     _capture_sync_marks

   LDMFD   R13!, {R_syncmark}		;restore the sync mark
   LDR     R0, sec_sync_mark		;check it is actually a sector ID
   TEQ     R0, R_curbit
   MVNNE   R0, #0			;NO, flush it then
   STRNE   R0, SiS
   ._byte_okay
   ;------------------------------------

   SUBS    R_sectorsize, R_sectorsize, #1	;reduce sectorsize counter
 BNE     _L1
 ._premature_sector_end

 MOV     R0, #16			;calc CRC on first CRC byte
 SUBS    R_bitsleft, R_bitsleft, R0	;reduce bit counter
 BMI     _shortSector			;exit if we run out of data
 BL      read_MFM			;read next byte
 MOV     R0, #16			;calc CRC on second CRC byte
 SUBS    R_bitsleft, R_bitsleft, R0	;reduce bit counter
 BLPL    read_MFM			;read next byte if data remaining
 ._shortSector

 LDR     R1, MFM_crc			;get the sector CRC
 TEQ     R1, #0				;is it valid?
 LDREQ   R0, [R_sectorinfo, #-8]	;YES, load the sector info
 BICEQ   R0, R0, #bit_sector_CRC	;|  clear sector CRC flag
 STREQ   R0, [R_sectorinfo, #-8]	;|+ store it

B       decodeMFM_exit





;MFM_find_sync
;-------------
;Searches forward one bit (one FM/MFM bit) at a time for a specific value
;
;Entry:
; R_syncmark - FM/MFM value to find
;
;Exit:
; R0 - corrupt
; R_bitsleft / R_curbit / R_nextbit / R_bitrot - updated

.MFM_find_sync
 STR     R14, [R13, #-4]!

 LDR     R_syncmark, bit_sync_mark	;bitsync value

 ._L1
   TEQ     R_curbit, R_syncmark		;look for sync
   LDREQ   PC, [R13], #4		;exit when found

   MOV     R0, #8			;start off with a byte shift
   BIC     R14, R_curbit, #%11111110 << 24
   TEQ     R14, R_syncmark, LSR #7
   MOVEQ   R0, #7			;and check for possible matches
   BIC     R14, R_curbit, #%11111100 << 24
   TEQ     R14, R_syncmark, LSR #6
   MOVEQ   R0, #6
   BIC     R14, R_curbit, #%11111000 << 24
   TEQ     R14, R_syncmark, LSR #5
   MOVEQ   R0, #5
   BIC     R14, R_curbit, #%11110000 << 24
   TEQ     R14, R_syncmark, LSR #4
   MOVEQ   R0, #4
   BIC     R14, R_curbit, #%11100000 << 24
   TEQ     R14, R_syncmark, LSR #3
   MOVEQ   R0, #3
   BIC     R14, R_curbit, #%11000000 << 24
   TEQ     R14, R_syncmark, LSR #2
   MOVEQ   R0, #2
   BIC     R14, R_curbit, #%10000000 << 24
   TEQ     R14, R_syncmark, LSR #1	;..down to 1 bit
   MOVEQ   R0, #1

   SUBS    R_bitsleft, R_bitsleft, R0	;reduce bit counter
   ADDMI   R13, R13, #4			;clear stack
   BMI     decodeMFM_exit		;exit if we run out of data

   BL      read_MFM
 B       _L1




;MFM_find_ID
;-----------
;Searches forward one byte (one FM/MFM word) at a time for a specific value
;
;Entry:
; R_syncmark - FM/MFM value to find
;
;Exit:
; R0 - corrupt
; R_bitsleft / R_curbit / R_nextbit / R_bitrot - updated

.MFM_find_ID
 STR     R14, [R13, #-4]!

 ._L1
   MOV     R0, #16			;skip the sector sync marker
   SUBS    R_bitsleft, R_bitsleft, R0	;reduce bit counter
   ADDMI   R13, R13, #4			;clear stack
   BMI     decodeMFM_exit		;exit if we run out of data

   BL      read_MFM			;read next byte

   MOV     R0, R_curbit, LSR #16
   TEQ     R0, R_syncmark		;look for mark
 BNE     _L1

LDR   PC, [R13], #4




;read_MFM
;--------
;Read R0 bits of MFM data
;
;Entry:
; R0 - bits to read
;
;Exit:
; R0-R2 corrupt
; R_curbit / R_nextbit / R_bitrot updated

.read_MFM
 STR     R14, [R13, #-4]!

 ._L1
   CMP     R0, #16			;if we're not reading a word
   BNE     _CRC_done			;we dont want to update the CRC

   LDR     R2, MFM_crc			;update CRC
   MOV     R1, R2, LSL #8		;R1 = CRC << 8
   AND     R1, R1, #&FF00
   MOV     R2, R2, LSR #8		;R2 = CRC >> 8

   STMFD   R13!, {R0, R1}
   MOV     R0, R_curbit, LSR #16
   BL      oddbits
   EOR     R2, R2, R0			;R2 = (CRC >> 8) ^ data
   LDMFD   R13!, {R0, R1}

   ADR     R14, crc_ccitt
   LDR     R14, [R14, R2, LSL #2]	;R14 = crc_ccitt[(CRC >> 8) ^ data]

   EOR     R2, R1, R14			;R2=(CRC<<8)^crc_ccitt[(CRC>>8)^data]

   STR     R2, MFM_crc
   ._CRC_done

   SUBS    R1, R_bitrot, R0		;enough bits for the request?
   MOVPL   R2, #0			;YES
   SUBMI   R2, R0, R_bitrot		;NO
   MOVMI   R0, R_bitrot			;use what's left and loop for rest

   SUBS    R_bitrot, R_bitrot, R0	;pull R0 bits into current buffer
   MOV     R_curbit, R_curbit, LSL R0
   ORR     R_curbit, R_curbit, R_nextbit, LSR R_bitrot
   LDRNE   PC, [R13], #4		;if bits left in secondary, exit

   LDR     R_bitrot, APD_File_Position	;position in track
   LDR     R_nextbit, [R_bitrot], #4	;load the next word
   STR     R_bitrot, APD_File_Position	;store updated ptr back

   EOR     R0, R_nextbit, R_nextbit, ROR #16	;convert from little endian
   BIC     R0, R0, #&00FF0000
   MOV     R_nextbit, R_nextbit, ROR #8
   EOR     R_nextbit, R_nextbit, R0, LSR #8

   MOV     R_bitrot, #32		;now have 32 bits remaining

   MOVS    R0, R2			;do we need more bits
 BNE     _L1				;YES, loop back

LDR     PC, [R13], #4

.crc_ccitt
INCBIN "<Tmp$Dir>.adffs.file_types.ccitt.crctable"




;oddbits
;-------
;Reduce a word to only it's odd bits
;
;Entry:
; R0 - value to reduce
;
;Exit:
; R0 = result
; R1 = corrupt

.oddbits				;optimized by Jeffrey Lee
 MOV    R1, #&55
 ORR    R1, R1, R1, LSL #8
 ORR    R1, R1, R1, LSL #16
 AND    R0, R0, R1
 ORR    R0, R0, R0, LSR #1

 MOV    R1, #&33
 ORR    R1, R1, R1, LSL #8
 ORR    R1, R1, R1, LSL #16
 AND    R0, R0, R1
 ORR    R0, R0, R0, LSR #2

 MOV    R1, #&0F
 ORR    R1, R1, R1, LSL #8
 ORR    R1, R1, R1, LSL #16
 AND    R0, R0, R1
 ORR    R0, R0, R0, LSR #4

 AND    R1, R0, #&00FF0000
 AND    R0, R0, #&000000FF
 ORR    R0, R0, R1, LSR #8
MOV    PC, R14
