#set R_buffer		= 4			; 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
#set R_crc_ccitt	= 5




;Entry:
; R0 - size to allocate
; R2 - file position pointer
;
;Exit:
; R0 - error or corrupt
; R1 - corrupt
; R2 - address of buffer
; R3 - size of buffer
; R4 - file position pointer
; MFM_Stream_Pos initiated

.allocate_temp_track
 STMFD   R13!, {R0, R2, R14}
 MOV     R3, R0				;bytes to read
 LDR     R2, [R12, #tmp_Track - VARS]	;temp buffer address
 LDR     R1, [R12, #tmp_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, #tmp_Track - VARS]	;clear pointer
 STR     R0, [R12, #tmp_Track_Length - VARS]

 MOV     R0, #Module_Claim		;claim more space
 SWI     XOS_Module			;PRM1-237
 LDMVSFD R13!, {R3, R4, PC}
 STR     R2, [R12, #tmp_Track - VARS]	;store address
 STR     R3, [R12, #tmp_Track_Length - VARS]	;store size

 ._Track_allocated
 STR     R2, [R12, #MFM_Stream_Pos - VARS]	;store file position pointer
LDMFD   R13!, {R3, R4, PC}




;Exit:
; R0 - preserved
; R2 - corrupt

.free_temp_track
 STMFD   R13!, {R0, R14}
 LDR     R2, [R12, #tmp_Track - VARS]	;temp buffer address
 TEQ     R2, #0				;did we allocate any
 MOVNE   R0, #0
 STRNE   R0, [R12, #tmp_Track - VARS]	;clear pointer
 STRNE   R0, [R12, #tmp_Track_Length - VARS]
 MOVNE   R0, #Module_Free		;yes, free it
 SWINE   XOS_Module			;PRM1-238

 LDR     R2, [R12, #tmp_Header - VARS]	;temp buffer address
 TEQ     R2, #0				;did we allocate any
 MOVNE   R0, #0
 STRNE   R0, [R12, #tmp_Header - VARS]		;clear pointer
 MOVNE   R0, #Module_Free		;free APD header
 SWINE   XOS_Module			;PRM1-238
LDMFD   R13!, {R0, PC}




;Entry:
; R2 - floppy type
; R12 - pointer to VARS

.floppy_type_changed
 STMFD   R13!, {R2, R14}
 STRB    R2, [R12, #Type_Mounted - VARS]	;inform DiscOp code its an HFE
 ADR     R14, _filetypes
 LDR     R2, [R14, R2, LSL #2]
 STR     R2, [R12, #FileType_Loaded - VARS]
 MOV     R2, #9
 STRB    R2, [R12, #Floppy_Changed - VARS]	;inform FileCore the disc has changed
LDMFD   R13!, {R2, PC}

._filetypes
DCD 0
DCB "ADF", 0
DCB "APD", 0
DCB "JFD "
DCB "HFEv"




;Entry:
; R12 - pointer to VARS
;
;Exit:
; R0-R3 - corrupt

.init_crc_ccitt
 STMFD   R13!, {R14}

 MOV     R0, #Module_Claim
 MOV     R3, #1024			;1KB for CRC table
 SWI     XOS_Module
 LDMVSFD R13!, {PC}
 STR     R2, [R12, #crc_ccitt - VARS]

 MOV     R3, #&1021 << 16
 MOV     R0, #255
 ._L1
   MOVS    R1, R0, LSL #25
   EORCS   R1, R1, R3
   EORMI   R1, R1, R3, LSR #1
   MOVS    R1, R1, LSL #2
   EORCS   R1, R1, R3
   EORMI   R1, R1, R3, LSR #1
   MOVS    R1, R1, LSL #2
   EORCS   R1, R1, R3
   EORMI   R1, R1, R3, LSR #1
   MOVS    R1, R1, LSL #2
   EORCS   R1, R1, R3
   EORMI   R1, R1, R3, LSR #1
   MOVS    R1, R1, LSL #1

   MOV     R1, R1, LSR #16
   STR     R1, [R2, R0, LSL #2]

   SUBS    R0, R0, #1
 BPL     _L1
LDMFD   R13!, {PC}




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

.decodeMFM
 STRB    R1, [R12, #current_density - VARS]	;store the density we're processing

 MOV     R1, #&A1				;converted 4489
 STR     R1, [R12, #SiS_syncmark - VARS]	;..used for nested sectors
 LDR     R1, _mfm_sync
 STR     R1, [R12, #bit_sync_mark - VARS]	;sync to this within bitstream
 LDR     R1, _mfm_sector
 STR     R1, [R12, #sec_sync_mark - VARS]	;MFM sector mark used in nested check
 LDR     R1, _mfm_sectorID
 STR     R1, [R12, #mfm5554 - VARS]		;sector ID mark
 LDR     R1, _mfm_data_mark
 STR     R1, [R12, #mfm5545 - VARS]		;MFM data mark
B       mFM_decode_track

._mfm_sync	DCD &44894489	;A1 A1
._mfm_sector	DCD &44895554	;A1 FE
._mfm_sectorID	DCD &5554	;FE
._mfm_data_mark	DCD &5545	;FB



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

.decodeFM
 STRB    R1, [R12, #current_density - VARS]	;store the density we're processing

 MOV     R1, #&00			;converted AAAA
 STR     R1, [R12, #SiS_syncmark - VARS]		;..used for nested sectors
 LDR     R1, _fm_sync
 STR     R1, [R12, #bit_sync_mark - VARS]	;sync to this within bitstream
 LDR     R1, _fm_sector
 STR     R1, [R12, #sec_sync_mark - VARS]	;MFM sector mark used in nested check
 LDR     R1, _fm_sectorID
 STR     R1, [R12, #mfm5554 - VARS]		;sector ID mark
 LDR     R1, _fm_data_mark
 STR     R1, [R12, #mfm5545 - VARS]		;MFM data mark
B       mFM_decode_track

._fm_sync	DCD &FFFFAAAA	;FF 00
._fm_sector	DCD &AAAAF57E	;00 FE
._fm_sectorID	DCD &F57E	;FE
._fm_data_mark	DCD &F56F	;FB




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

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

 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, [R12, #sector_timing - VARS]

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

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

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




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

.decode_mFM_find_sector
 BL      MFM_find_sync

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

 LDR     R_syncmark, [R12, #mfm5554 - VARS]		;look for ID mark
 BL      MFM_find_ID
 
 LDRB    R0, [R12, #current_density - VARS]
 TEQ     R0, #1				;are we processing FM?
 MVNEQ   R0, #0				;YES
 MOVEQ   R0, R0, LSR #16		;...reset CRC to FFFF
 STREQ   R0, [R12, #MFM_crc - VARS]

 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>
 AND     R1, R0, #&FF			;R1 = sector size
 CMP     R1, #13-7			;sanity check sector size<=8192 bytes
 BHI     decode_mFM_find_sector

#if debug_1772 == 1
SWI &100+ASC("s")
MOV R1, R0, LSR #8
BL outputHexTruncated
SWI &100+ASC(".")
AND R1, R0, #&FF
ADD R1, R1, #7
BL outputHexTruncated
#endif
 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, [R12, #sector_timing - VARS]	;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, [R12, #MFM_crc - VARS]
 EORS    R1, R1, R0			;is the CRC ok?
 LDR     R0, [R13], #4			;| restore R0
 LDRB    R1, [R12, #current_density - VARS]	;| 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, [R12, #ADF_Buffer_Address - VARS]	;| 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, [R12, #MFM_crc - VARS]

 LDR     R_syncmark, [R12, #mfm5545 - VARS]	;look for data mark
 BL      MFM_find_ID
#if debug_1772 == 1
SWI &100+ASC(" ")
#endif

 LDRB    R0, [R12, #current_density - VARS]
 TEQ     R0, #1				;are we processing FM?
 MVNEQ   R0, #0				;YES
 MOVEQ   R0, R0, LSR #16		;...reset CRC to FFFF
 STREQ   R0, [R12, #MFM_crc - VARS]

 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, [R12, #bit_sync_mark - VARS]	;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
   BL      _store_byte

   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

   ADD     R2, R12, #SiS - VARS		;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, [R12, #MFM_Stream_Pos - VARS]	;get the current position
   STMIA   R2, {R0, R_bitrot, R_nextbit, R_bitsleft}
   ._capture_sync_marks
     LDR     R0, [R12, #SiS_syncmark - VARS]	;store the sync mark in the data
     BL      _store_byte

     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, [R12, #sec_sync_mark - VARS]	;check it is actually a sector ID
   TEQ     R0, R_curbit
   MVNNE   R0, #0			;NO, flush it then
   STRNE   R0, [R12, #SiS - VARS]
   ._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, [R12, #MFM_crc - VARS]	;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

._store_byte
 STRB    R0, [R_buffer], #1

 LDR     R0, [R12, #DA_address - VARS]
 LDR     R1, [R12, #DA_size - VARS]
 ADD     R0, R0, R1
 TEQ     R_buffer, R0			;have we exceeded the buffer?
 MOVNE   PC, R14			;NO

 STMFD   R13!, {R4-R5, R14}
 ADD     R4, R1, #32 * 1024		;extend buffer
 LDR     R5, [R12, #ADF_Buffer_Address - VARS]	;preserve as its about to be reset
 BL      MemAlloc
 STR     R5, [R12, #ADF_Buffer_Address - VARS]
 LDMVCFD R13!, {R4-R5, PC}

 ADR     R0, Error_MemAlloc
 SWI     OS_GenerateError




;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, [R12, #bit_sync_mark - VARS]	;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
; R12 - pointer to VARS
;
;Exit:
; R0-R2 corrupt
; R_curbit / R_nextbit / R_bitrot updated

.read_MFM
 STMFD   R13!, {R_crc_ccitt, R14}

 LDR     R_crc_ccitt, [R12, #crc_ccitt - VARS]
 ._L1
   CMP     R0, #16			;if we're not reading a word
   BNE     _CRC_done			;we dont want to update the CRC

   LDR     R2, [R12, #MFM_crc - VARS]	;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}

   LDR     R14, [R_crc_ccitt, R2, LSL #2]	;R14 = crc_ccitt[(CRC >> 8) ^ data]
   EOR     R2, R1, R14			;R2=(CRC<<8)^crc_ccitt[(CRC>>8)^data]
   STR     R2, [R12, #MFM_crc - VARS]
   ._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
   LDMNEFD R13!, {R_crc_ccitt, PC}	;if bits left in secondary, exit

   LDR     R_bitrot, [R12, #MFM_Stream_Pos - VARS]	;position in track
   LDR     R0, [R_bitrot], #4				;load the next word
   STR     R_bitrot, [R12, #MFM_Stream_Pos - VARS]	;store updated ptr back
   BL      little_endian
   MOV     R_nextbit, R0
   MOV     R_bitrot, #32		;now have 32 bits remaining

   MOVS    R0, R2			;do we need more bits
 BNE     _L1				;YES, loop back
LDMFD   R13!, {R_crc_ccitt, PC}




;little_endian
;-------------
;converts a little endian word to big endian
;
;Entry:
; R0 - value to convert
;
;Exit:
; R0 - result
; R1 - corrupt

.little_endian
 EOR     R1, R0, R0, ROR #16
 BIC     R1, R1, #&00FF0000
 MOV     R0, R0, ROR #8
 EOR     R0, R0, R1, LSR #8
MOV     PC, R14




;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




;clear_track_sector_table
;------------------------
;marks all tracks and sectors as non-existant
;
;Entry:
; R2 - start of area
; R3 - size of area
;
;Exit:
; R0, R2, R3 - corrupt

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