		save
	if DontListIncls
		listing off
	endif

;********************************************************************
;
; This file contains definitions for both the code inside the Z8
; 341-0288-A and the external EPROM 341-0289-D or 1A45-D.
;
; At Apple, both the intenal and external ROM code were generated
; from a common source, but here we have two separate assembler
; files.
;
; 2011-08-10 PS
; last changes 2013-07-30 PS
;
;********************************************************************

EpromSize 	EQU 4096		; per bank
MaxEpromAddress EQU EpromSize-1
EpromStartAdr	EQU 00001h	
EpromOffset 	EQU 01000h
RamOffset 	EQU 01000h
RamSize 	EQU 2048		; Physical length of 6116 (2kx8)
HiRamAdr 	EQU RamSize-1

Stack_Top 	EQU 080h		; Register 07Fh +1
Init_Pc 	EQU 00Ch		; Initial PC setting after RESET



;********************************************************************
;
; Hardware
;
;********************************************************************
;
;	I/O Port	Use
;	--------	---
;	   0		Bit 0: Adr8
;	{Output}	Bit 1: Adr9
;			Bit 2: Adr10 / RWI- (RWI: reduced write current)
;			Bit 3: Adr11 / PC-  (PC: pre-compensation)
;			Bit 4: Servo_Reset-
;			Bit 5: Format_Enable-
;			Bit 6: Z8_Test-
;			Bit 7: Read_Header
;
;	   1 		Bit 0: Adr0 / Apple_Bus0
;    {Input/Output}	Bit 1: Adr1 / Apple_Bus1
;			Bit 2: Adr2 / Apple_Bus2
;			Bit 3: Adr3 / Apple_Bus3
;			Bit 4: Adr4 / Apple_Bus4
;			Bit 5: Adr5 / Apple_Bus5
;			Bit 6: Adr6 / Apple_Bus6
;			Bit 7: Adr7 / Apple_Bus7
;
;	   2 		Bit 0: Start-
;    {Input/Output}	Bit 1: EccError-
;			Bit 2: Command {Input}
;			Bit 3: Busy
;			Bit 4: Msel0
;			Bit 5: Msel1
;			Bit 6: SioRdy {Input}
;			Bit 7: Disk_RW-
;
;	   3		Bit 0: SioDataIn {Input}
;    {Input/Output}	Bit 1: Sector {Input}
;			Bit 2: Index {Input}
;			Bit 3: Sector_Done
;			Bit 4: Data_Memory_Select
;			Bit 5: Head_Select
;			Bit 6: Z8_RW_Clock
;			Bit 7: SioDataOut
;

; Port 0 Defs:
TimeOut 	EQU 001h	; hardware timeout flag
EccTest 	EQU 002h	; Active Low to Ecc gate array chip
RWI 		EQU 004h	; Reduced Write Current {active low}
PC 		EQU 008h	; Write Pre-compensation {active low}
ServoRst 	EQU 000h	; Servo Reset {active low}
Not_ServoRst 	EQU 010h
Not_FmenL 	EQU 020h	; Format Enable {active low}
FmenL 		EQU 000h
AcEraseL 	EQU 020h
Not_AcEraseL 	EQU 000h
Z8TestL 	EQU 000h	; Z8 Test switch {1=normal, 0=test}
Not_Z8TestL 	EQU 040h
RdHdrH 		EQU 080h	; State Machine: Ignore Header
Not_RdHdrH 	EQU 000h	;                {active hi}

; Port 1 Defs:
; {none}

; Port 2 Defs:
StartL 		EQU 000h	; State Machine: start Execution
Not_StartL 	EQU 001h	;                {active low}
EccError 	EQU 000h	; Flags Ecc circuitry {active low}
Not_EccError 	EQU 002h
Cmd 		EQU 004h	; Apple i/o signal: CMD {active hi}
Bsy 		EQU 008h	; Apple i/o signal: BSY {active hi}
Not_Bsy 	EQU 000h
Msel0 		EQU 010h	; Memory Select bit 0
Msel1 		EQU 020h	; Memory Select bit 1
Apple_Mem 	EQU 000h	;   Mem <--> Apple
Z8_Mem 		EQU 010h	;   Mem <--> Z8
Disk_Mem 	EQU 020h	;   Mem <--> State Machine (Disk)
Z8_Apple 	EQU 030h	;   Z8  <--> Apple
SioRdy 		EQU 040h	; Servo's Sio is ready {active hi}
DrwL_Read 	EQU 080h	; State Machine: Disk Read/Write
DrwL_Write 	EQU 000h	;                {Write active lo}
P21_In 		EQU 002h	; Port 2 Bit 1 is an input
P22_In 		EQU 004h	; Port 2 Bit 2 is an input
P26_In 		EQU 040h	; Port 2 Bit 6 is an input

; Port 3 Defs:
SectorMark 	EQU 002h	; Sector Mark from drive {active hi}
IndexMark 	EQU 004h	; Index Mark from drive {active hi}
SectDnL		EQU 008h	; Sector Done {active low}
Dm 		EQU 010h	; Data Memory selected {active low}
Hs0 		EQU 020h	; Head select {O=head_0, 1=head_1}
Zrwck 		EQU 040h	; Z8 test clock for state machine

; Controller Status Port
StatusPort	EQU 01F00h
CrcErrL		EQU 080h	; status bit 7: Crc Error {active lo}
WrtNvldL	EQU 040h	; status bit 6: Write Not Valid {active lo}
ServoRdy	EQU 020h	; status bit 5: Servo Ready {active hi}
ServoErr	EQU 010h	; status bit 4: Servo Error {active hi}
Ymask		EQU 00Fh	; mask for status bits 0:3: state
Norm_State	EQU 002h	;   normal end state for Read, Write, ReadHdr
NormFmt_State	EQU 00Ah	;   normal end state for Format
NoHdr_State	EQU 000h	;   last state if no matching header found
Start_State	EQU 000h	;   beginning state machine state

; Bank Switch Register
BankReg 	EQU 01800h	; address of first bank bit
Led 		EQU 01800h	; address of Led bit
Led_Mask	EQU 0FEh	; mask for Led bit

RamBank0 	EQU 01900h	; address of first Ram_Bank bit
Ram0 		EQU 00h		; offset of ram bank zero
Ram1 		EQU 01h
Ram2 		EQU 02h
Ram3 		EQU 03h

RomBank0 	EQU 01E00h
RomBank2 	EQU 01D00h
Eppom0 		EQU 00h
Eprom1 		EQU 01h
Eprom2 		EQU 02h
Eprom3 		EQU 03h
Eprom4 		EQU 04h



;********************************************************************
;
; Registers
;
;********************************************************************

; working register sets R0:15 (select by setting RP)
Wrk_Io		EQU 000h	; Working regs set 0 = I/O and scratch
Wrk_Sys 	EQU 010h	; Working regs set 1 = System
Wrk_Except 	EQU 020h	; Working regs set 2 = Exception set
Wrk_Sys2 	EQU 030h	; Working regs set 3 = System2
Wrk_Scr 	EQU 040h	; Working regs set 4 = Scratch set
Wrk_Cntrl	EQU 0F0h	; Working regs set F = control set

Hi_Rwi_Reg 	EQU 020h	; holds cylinder value for RWI and PC
Lo_Rwi_Reg 	EQU 021h

PSector 	EQU 022h	; last physical sector
Free_SlfTst 	EQU 023h	; pointer to selftest routine

Excpt_Stat 	EQU 024h	; exception status register
Recovery 	EQU 080h	;   global recovery bit {active hi}
SprTbl_Warn 	EQU 040h	;   spare table is almost full
Buf_Damage 	EQU 020h	;   StMach entry buffer is not zero
PwrRst	 	EQU 010h	;   Widget was power reset
NZero_Stat 	EQU 008h	;   last system status was non-zero
LedStat 	EQU 001h	;   state of LED on controller

SlfTst_Result 	EQU 025h	; results of self test
Ram_Fail 	EQU 080h	;   writeable memory failure
Eprom_Fail 	EQU 040h	;   Eprom checkbyte mismatch
Disk_Speed 	EQU 020h	;   Disk not up to speed
Servo_Fail 	EQU 010h	;   Servo is not healthy
Sector_Cnt 	EQU 008h	;   Not enough sectors!
State_Fail 	EQU 004h	;   State machine not healthy
Rw_Fail		EQU 002h	;   can't read/write!
No_SprTbl	EQU 001h	;   No Spare Table found!

RdStat 		EQU 026h	; status of last read operation
RdErrCnt 	EQU 027h	; number of retries of last read
WrStat 		EQU 028h	; status of last write operation
WrErrCnt 	EQU 029h	; number of retries of last write
SeekCount	EQU 02Ah	; number of seeks since last arm swing

PwrFlg0 	EQU 02Ch	; power on flag
PwrFlg1 	EQU 02Dh
PwrFlg2 	EQU 02Eh
PwrFlg3 	EQU 02Fh

Dmt_Counter 	EQU 036h	; double register counter
Scr_Cntr 	EQU 038h	; double register counter

Cur_Cyl 	EQU 050h

Cylinder	EQU 052h
Head		EQU 054h
Sector		EQU 055h

DiskStat	EQU 056h	; current state of some disk params
On_Track	EQU 080h	;   software on-track flag
RdHdrRecal	EQU 040h	;   read the header after a recal operation
Wr_Op		EQU 020h	;   current access is for a write
Parked		EQU 010h	;   heads are currenly parked
Seq_CachSrch	EQU 008h	;   search the cache sequentially
MultiBlk	EQU 004h	;   MultiBlock semaphore
SeekComplete	EQU 002h	;   head/arm is not in motion
Offset_On	EQU 001h	;   Auto-Ofset is currently on

Seek_Type   	EQU 057h	; Seek w/wo Auto-Offset
Data_Type   	EQU 058h	; Spare Table or User Block
Unused_Reg   	EQU 059h	; reflection of bank register

BlkStat   	EQU 05Ah	; current state of cache logical block
CachSeek   	EQU 080h	;   a seek is needed for this block
CachHdChg   	EQU 040h	;   a head change is needed for this block
S_Block    	EQU 001h	;   this block is a spare block
B_Block    	EQU 002h	;   this block is a bad block

Cache_Index 	EQU 05Bh	; Index into cache assuming sequential search

Lst_HiCyl  	EQU 05Ch	; previous seek address
Lst_LoCyl  	EQU 05Dh
Lst_Head  	EQU 05Eh
Lst_Sector  	EQU 05Fh

P01M_Image   	EQU 004h
P3M_Image   	EQU 005h
P01M_StMach   	EQU 006h
P3M_StMach   	EQU 007h
Dm_Mask   	EQU 008h
Start_Mask   	EQU 009h

ScrReg0 	EQU 040h	; Scratch register 0
ScrReg1    	EQU 041h	; Scratch register 1
ScrReg2     	EQU 042h	; Scratch register 2
ScrReg3     	EQU 043h	; Scratch register 3
ScrReg4     	EQU 044h	; Scratch register 4
ScrReg5     	EQU 045h	; Scratch register 5
ScrReg6     	EQU 046h	; Scratch register 6
ScrReg7     	EQU 047h	; Scratch register 7
ScrReg8     	EQU 048h	; Scratch register 8
ScrReg9     	EQU 049h	; Scratch register 9
ScrRegA     	EQU 04Ah	; Scratch register A
ScrRegB     	EQU 04Bh	; Scratch register B
ScrRegC     	EQU 04Ch	; Scratch register C
ScrRegD     	EQU 04Dh	; Scratch register D
ScrRegE     	EQU 04Eh	; Scratch register E
ScrRegF     	EQU 04Fh	; Scratch register F



;********************************************************************
;
;    Constant Definitions
;
;********************************************************************

IntL_Dflt 	EQU 2			; assume drive interleaved 1:1
Map_Dflt 	EQU 0Ch			; Map 5:1 onto 2:1 as default

RegLpTimes 	EQU 2			; Loop twice (0's and 1's)
RegCount 	EQU 128			; Total number of regs: Z8
RegUsed 	EQU 5			; this test uses r4, r5, r6, r7, r8
I_OregUsed 	EQU 4			; Ports O, 1, 2, 3 can't be tested here
HiRegAdr 	EQU RegCount-1

RamLpTimes 	EQU 2			; loop twice (0's and 1's)


Max_Cmnd_Types 	EQU 002h		; currently only three types of cmnds
CmndType 	EQU 0F0h		; mask for TYPE of command
Cmnd_Len 	EQU 007h
Servo_Len 	EQU 005h
NbrZones 	EQU 16			; 16 zones for manual offset
ZoneShift 	EQU 5			; use this shift value to divide
MinOffset 	EQU 10			; manual offset only if greater than 10

MaxChkBad	EQU 10			; check bad blocks if less then 10



Pro_Cmnds 	EQU 02			; number of commands implemented
Diag_Cmnds 	EQU 19
Sys_Cmnds 	EQU 02

	if W_10MB
HiMaxLogical 	EQU 000h	; highest user block =004BFF
MidMaxLogical 	EQU 04Bh
LoMaxLogical 	EQU 0FFh
HiMaxCyl 	EQU 002h	; highest cylinder = 0220 (544)
LoMaxCyl 	EQU 020h
MaxSeek 	EQU 0185h	; seeks longer than this are broken into 2
Mid_CyI 	EQU 0101h	; middle of data area
Init_HiCyl 	EQU 001h	; initial setting for data cylinder
Init_LoCyl 	EQU 0F9h
Tst_HiCyl 	EQU 002h	; Cyl, Head, and sector of R/W test area
Tst_LoCyl 	EQU 005h
Tst_Head 	EQU 000h
Tst_Sctr 	EQU 000h
NbrSctrs 	EQU 19		; number of sectors = 19
NbrHds 		EQU 2		; number of heads = 2
NbrTracks 	EQU 514		; number of tracks = 514
HiSpr0 		EQU 000h	; logical block of Spr(0)
MidSpr0 	EQU 019h
LoSpr0 		EQU 055h
HiSpr1		EQU 000h	; logical block of Spr(1)
MidSpr1 	EQU 032h
LoSpr1 		EQU 0AAh
RWI_Cylinder	EQU 257		; cylinder at which to turn on RWI and PC
ParkCyl 	EQU 00235h	; cylinder to park heads at
	endif

	if W_20MB
HiMaxLogicalI 	EQU 000h	; highest user block =00984B
MidMaxLogical 	EQU 098h
LoMaxLogical 	EQU 04Bh
HiMaxCyl 	EQU 002h	; highest cylinder = 0220 (544)
LoMaxCyl 	EQU 020h
MaxSeek 	EQU 0185h	; seeks longer than this are broken into 2
Mid_CyI 	EQU 0101h	; middle of data area
Init_HiCyl 	EQU 001h	; initial setting for data cylinder
Init_LoCyl 	EQU 0F9h
Tst_HiCyl 	EQU 002h	; Cyl, Head, and sector of R/W test area
Tst_LoCyl 	EQU 005h
Tst_Head 	EQU 000h
Tst_Sctr 	EQU 000h
NbrSctrs 	EQU 38		; number of sectors = 38
NbrHds 		EQU 2		; number of heads = 2
NbrTracks 	EQU 514		; number of tracks = 514
HiSpr0 		EQU 000h	; logical block of Spr(0)
MidSpr0 	EQU 032h
LoSpr0 		EQU 0AAh
HiSpr1		EQU 000h	; logical block of Spr(1)
MidSpr1 	EQU 065h
LoSpr1 		EQU 054h
RWI_Cylinder	EQU 257		; cylinder at which to turn on RWI and PC
ParkCyl 	EQU 00235h	; cylinder to park heads at
	endif

	if W_40MB
HiMaxLogical 	EQU 001h	; highest user block =0130E3
MidMaxLogical 	EQU 030h
LoMaxLogical 	EQU 0E3h
HiMaxCyl 	EQU 004h	; highest cylinder = 0440 (1088)
LoMaxCyl 	EQU 040h
MaxSeek 	EQU 030Ah	; seeks longer than this are broken into 2
Mid_CyI 	EQU 0202h	; middle of data area
Init_HiCyl 	EQU 003h	; initial setting for data cylinder
Init_LoCyl 	EQU 0F9h
Tst_HiCyl 	EQU 004h	; Cyl, Head, and sector of R/W test area
Tst_LoCyl 	EQU 00Ah
Tst_Head 	EQU 000h
Tst_Sctr 	EQU 000h
NbrSctrs 	EQU 38		; number of sectors = 38
NbrHds 		EQU 2		; number of heads = 2
NbrTracks 	EQU 1028	; number of tracks = 1028
HiSpr0 		EQU 000h	; logical block of Spr(0)
MidSpr0 	EQU 065h
LoSpr0 		EQU 054h
HiSpr1		EQU 000h	; logical block of Spr(1)
MidSpr1 	EQU 0CAh
LoSpr1 		EQU 0A8h
RWI_Cylinder	EQU 514		; cylinder at which to turn on RWI and PC
ParkCyl 	EQU 0046Ah	; cylinder to park heads at
	endif


SprThresh 	EQU 3 		; this many CRC errors to be candidate for sparing

Write_Op 	EQU 000h 	; current operation is a write
Read_Op 	EQU 080h	; current operation is a read

Wait 		EQU 040h	; wait for seek-end


; >>> "SpareTable" array element flags (byte 0)
Nil 		EQU 080h	; Nil Ptr
Used  		EQU 040h	; Spare Block in table is used
Useable  	EQU 020h	; Spare Block in table is useable (not a bad block itself)
Spare 		EQU 010h	; element is a true spare
BadBlock 	EQU 000h	; element is a bad block
SprTbl_Type 	EQU 008h	; type of element is spare table
ID_Type 	EQU 004h	; type of element is ID block
User_Type 	EQU 002h	; type of element is User data block

Found 		EQU 001h	; Block was found in spare table
Random 		EQU 080h	; search cache by index

TestBitMap 	EQU 080h	; check bit map location for 0 or 1
SetBitMap 	EQU 040h	; set a bit map location
ClearBitMap	EQU 020h	; clear a bit map location

BlockLength 	EQU 1+532+2+6 	; Length = Dummy + Data + CRC + ECC

RdError 	EQU 080h
RdSrvoErr 	EQU 040h
RdSuccess 	EQU 020h
RdNoHdrFnd 	EQU 010h
RdCrcErr 	EQU 008h

RdHError 	EQU 080h
RdHSrvoErr 	EQU 040h

WrError 	EQU 080h
WrSrvoErr	EQU 040h
WrSuccess	EQU 020h
WrNoHdrFnd 	EQU 010h

FmtError 	EQU 080h
FmtSrvoErr 	EQU 040h
FmtSuccess 	EQU 020h
Max_Interleave 	EQU 006h

Cmnd_Pending 	EQU 080h	; Wait_Cmnd was called from a command
IBsy 		EQU 040h	; set BSY
MultiWr 	EQU 020h	; current operation is MultiBlockWrite

Frst_SprTbl 	EQU 080h	; First spare table has been found


; >>> Data Exception Error Codes
Error 		EQU 080h
Ex_Undetermined EQU 000h	; Undetermined error (recovery off?)
Ex_SprBlock 	EQU 002h	; Spare this block!
Ex_BadBlock 	EQU 004h	; make this block a bad block
Ex_ReadErr 	EQU 006h	; non-catastophic error during read
Ex_HdrBad 	EQU 008h	; make this block bad because no header
Ex_HdrSpr 	EQU 00Ah	; spare this block because no header

Ex_Case_Max 	EQU 00Ah	; maximum case values


; >>> Interface Responses
Read_Response 	EQU 002h	; Interface Response to a Read command
Wr_Response 	EQU 003h 	; Interface Response to a Write command
WrVer_Response 	EQU 004h	; Interface Response to a Write Verify command
End_Wr_Response EQU 006h	; Interface response after receiving wr data
D_R_ID_Response EQU 002h
Rd_Stat_Resp 	EQU 003h
Rd_SStat_Resp 	EQU 004h
Sd_S_C_Resp 	EQU 005h
S_Seek_Response EQU 006h
S_Rstr_Response EQU 007h
Set_Rcvr_Resp 	EQU 008h
S_Park_Resp 	EQU 00Ah
D_Read_Response EQU 00Bh
D_RdHdr_Resp 	EQU 00Ch
D_Write_Resp 	EQU 00Dh
St_Map_Response EQU 00Eh
St_AO_Response	EQU 00Eh
D_R_Spr_Resp	EQU 00Fh
Wr_Spr_Resp	EQU 010h
Fmt_Response 	EQU 011h
I_Spr_Response 	EQU 012h
Rd_Abrt_Resp 	EQU 013h
RstSrvo_Resp 	EQU 014h
D_Scan_Response EQU 015h

Sys_Rd_Resp 	EQU 022h
Sys_Wr_Resp 	EQU 023h
Sys_WrEx_Resp 	EQU 0A3h
Sys_WrEnd_Resp 	EQU 027h
Sys_WrVer_Resp 	EQU 024h

ProFile 	EQU 000h	; Device Interface Type is ProFile
Widget 		EQU 001h	; Device Interface Type is Widget

Pro_Log_Offset 	EQU 001h	; offset from start of command to blocknumber
Sys_Log_Offset 	EQU 003h

Inc_SprCnt 	EQU 000h
Inc_BadCnt 	EQU 001h
Dec_BadCnt 	EQU 002h


; >>> System Status Definitions
; Byte 0
Bad_55 		EQU 080h	; Status: Other than 55 response from host
WrBuf_OR 	EQU 040h	; Status: Write Buffer Overflow
Stat_Rd_Err	EQU 008h	; Status: Read Error
Stat_No_Hdr 	EQU 004h	; Status: No Header Found
Stat_Srvo 	EQU 002h	; Status: Unrecoverable Servo Error
Op_Failed 	EQU 001h	; Status: Operation Failed

; Byte 1
SprBlk_Hard 	EQU 040h	; Status: no room left in spare table
SprBlk_Warn 	EQU 020h	; Status: 5 or less spare blocks available
Stat_SlfTst 	EQU 008h	; Status: Abort caused by self test failure
Stat_Spare 	EQU 004h	; Status: Sparing has occured
Stat_Seek 	EQU 002h	; Status: Seek to wrong track
Stat_Abort 	EQU 001h	; Status: Controller aborted

; Byte2
Power_Reset 	EQU 080h	; Widget was power reset
Illegal_Block 	EQU 040h	; Status: Block number out of bounds

; Byte3
EccStat 	EQU 080h	; read error detected by ecc
CrcStat 	EQU 040h	; read error detected by crc
Hdr_MisMatch	EQU 020h	; timeout waiting for header


; >>> Dead Man Timer (Watchdog)
Dmt_PosHeads 	EQU 00h
Dmt_C00 	EQU 01h 	; Command $00
Dmt_C01 	EQU 02h		; Command $01
Dmt_C02 	EQU 03h 	; Command $02
Dmt_ReadBlock 	EQU 04h		; Routine: ReadBlock
Dmt_ReadHdr 	EQU 05h		; Routine: ReadHdr
Dmt_WriteBlock 	EQU 06h		; Routine: WriteBlock
Dmt_FormatBlock EQU 07h		; Routine: FormatBlock
Dmt_FmtTrack 	EQU 08h		; Routine: FormatTrack
Dmt_LctSctr 	EQU 09h		; Routine: LocateSector
Dmt_Recal 	EQU 0Ah		; Routine: Restore
Dmt_WV 		EQU 0Bh		; Routine: WriteVerify
Dmt_S_R 	EQU 0Ch		; Routine: ServoRecovery
Dmt_OverLap 	EQU 0Dh		; Routine: OverLappedSeek
Dmt_Rd_Common 	EQU 0Eh 	; Routine: Read_Common
Dmt_Seek 	EQU 0Fh		; Routine: Seek
Dmt_ServoOk 	EQU 10h		; Routine: ServoOk
Dmt_Wr_Common 	EQU 11h 	; Routine: Write_Common
Dmt_Trk_Cnt 	EQU 12h 	; Routine: TrackCount
Dmt_S_Cmnd 	EQU 13h 	; Routine: ServoCmnd
Dmt_S_Stat 	EQU 14h		; Routine: ServoStatus
Dmt_S_Store 	EQU 15h 	; Routine: ServoStore
Dmt_S_Load 	EQU 16h 	; Routine: ServoLoad

Dmt_Val 	EQU 500 	; DeadManTimer count


; >>> Exception Stuff
Apl_Ack 	EQU 055h 	; Acknowledge from Host
Init_Response 	EQU 001h	; Controller Ready for new command
Free_Proc 	EQU 069h	; Host willing to give up the bus

Apl_Excpt 	EQU 000h 	; Apple_lnterface
ChkB_Mismatch 	EQU 000h	;   Check Byte Mismatch
Bad_Cmnd 	EQU 001h	;   Illegal Command
Cmnd_Excpt 	EQU 001h	; Command_Driver
Strt_Cmnd 	EQU 000h	;   Start_Command
LBlk_Bounds 	EQU 002h	; Logical Block out-of-bounds
S_Rst_Abort 	EQU 003h	; Servo Reset Abort
Serr_NotReady	EQU 000h	;   abort because NOT(ServoRdy) OR ServoErr
Comm_Err 	EQU 001h	;   abort because communication error
S_Store 	EQU 000h	; comm error in Servo Store
S_Load 		EQU 001h	; comm error in Servo Load
RdBlk_Abort 	EQU 004h	; abort in ReadBlock
RdHdr_Abort 	EQU 005h	; abort in ReadHeader
WrBlk_Abort 	EQU 006h	; abort in WriteBlock
FmtBlk_Abort 	EQU 007h	; abort in FormatBlock
Bad_State 	EQU 000h	;   abort caused by illegal state machine state
FmtTrk_Abort 	EQU 008h	; abort in FomatTrack
FmtTrk_PosErr 	EQU 000h	;   abort because unable to position heads
SpareAbort 	EQU 009h	; abort while trying to deal with spare table
NoSpace 	EQU 000h	;   abort was caused by request for space
Srvo_R_Abort	EQU 00Ah	; abort while attempting Servo Recovery
OvrLp_Abort 	EQU 00Bh	; abort while attempting overlapped seek
Rd_Cmn_Abort 	EQU 00Ch	; abort while executing system read
Servo_Dead 	EQU 000h	;   aborted because of servo failure
Seek_Abort 	EQU 00Dh	; abort while executing a seek
Wr_Cmn_Abort 	EQU 00Eh	; abort while executing Write-Common
Bad_PassWord 	EQU 00Fh	; command string had wrong password
Bad_Params 	EQU 010h	; command had illegal parameters
SprCnt_Abort 	EQU 011h	; illegal spare count command
Host_OvrFlow 	EQU 012h	; Host sent too much data!



;********************************************************************
;
; External Ram Stuff
;
;********************************************************************

		ORG 01000h
ReadArray
RSctrGap  	DB 10 dup(?)
RHdrGap  	DB 1 dup(?)
RHeader  	DB 6 dup(?)
RDataGap  	DB 7 dup(?)
RDummy  	DB 1 dup(?)
RBuffer1  	DB 532 dup(?)		; (1019h)
RBuf1Crc  	DB 2 dup(?)
RBuf1Ecc  	DB 6 dup(?)
REndGap  	DB 1 dup(?)
RBuf1Pw  	DB 4 dup(?)

StatusArray 	EQU RBuffer1 -4		; we insert status here before it is DMAed to the host


		ORG 01000h
ReadHdrArray
RHSctrGap	DB 10 dup(?)
RHHdrGap 	DB 2 dup(?)
RHHeader 	DB 6 dup(?)
RHDataGap 	DB 6 dup(?)
RHDummy		DB 1 dup(?)
RHBuffer1 	DB 532 dup(?)		; (1019h)
RHBuf1Crc 	DB 2 dup(?)
RHBuf1Ecc 	DB 6 dup(?)
RHEndGap 	DB 1 dup(?)
RHBuf1Pw 	DB 4 dup(?)

RdH_Stat_Array 	EQU RHHeader -4		; we insert status here before it is DMAed to the host


		ORG 01000h
WriteArray
WSctrGap	DB 10 dup(?)
WHdrGap 	DB 1 dup(?)
WHeader 	DB 6 dup(?)
WDataGap 	DB 14 dup(?)
WDataSync 	DB 2 dup(?)
WBuffer1 	DB 532 dup(?)		; (1021h) write data from host goes here (by DMA)
WBuf1Crc 	DB 2 dup(?)
WBuf1Ecc 	DB 6 dup(?)
WEndGap 	DB 2 dup(?)
WBuf1Pw 	DB 4 dup(?)

Cmnd_Ptr 	EQU WBuffer1 -7		; (101Ah)  host passes command here!


		ORG 01000h +32
FormatArray
FSctrGap	DB 10 dup(?)
FHdrGap 	DB 16 dup(?)		; header gap: 16x 00
FHdrSync 	DB 2 dup(?)		; header sync: 01 00
FHeader 	DB 6 dup(?)
FDataGap 	DB 14 dup(?)
FDataSync 	DB 2 dup(?)		; data sync: 01 00
FBuffer1 	DB 532 dup(?)		; (1052h)
FBuf1Crc 	DB 2 dup(?)
FBuf1Ecc 	DB 6 dup(?)
FEndGap 	DB 2 dup(?)

WrBlkFence 	DB 4 dup(?) 		; (1270h)  fence to check for host write overruns


Buf2Array
BufDummy 	DB 1 dup(?)
Buffer2 	DB 532 dup(?)		; (1275h)
Buf2Crc 	DB 2 dup(?)
Buf2Ecc 	DB 6 dup(?)
Buf2Pw2 	DB 4 dup(?)

CStatus0 	DB 4 dup(?)		; (1495h)  Controller Status
CStatus1 	DB 4 dup(?)
CStatus2 	DB 4 dup(?)
CStatus3 	DB 4 dup(?)		; (14A1h)  Last Requested Block Number
CStatus4 	DB 4 dup(?)		; (14A5h)  Last Host Command, byte 0..3
CStatus5 	DB 4 dup(?)		;          Last Host Command, byte 4..7
CStatus6 	DB 4 dup(?)
End_CStatus 	EQU $

LogicalBlock 	EQU CStatus3

SrvoCmndBuf 	DB 5 dup(?)		; (14B1h)  Servo Command Buffer
S_Cmnd_Len 	EQU 5			; Length of ServoCmndBuffer
SStatus0	DB 5 dup(?)		; (14B6h)  Servo Status


; >>> Spare Table
; 
; To see if any block has been spared, its LBA is divided by 0400h. The result
; is used as an index into "SegPtrArray". Here we have an entry for each 1024 
; block area (i.e. any block that has identical LBA bits 16:10).
; If this entry is Nil (080h), no block in this area has been spared. Any 
; value <> Nil is a pointer "HeadPtr" into "SpareTable".
;
; "SpareTable" consists of 76 four-byte entries, one for each spare block:
;  byte 0: flags, bit 7 set if last entry in chain
;  byte 1: LBA bit 9:8 of block that has been replaced by this spare
;  byte 2: LBA bit 7:0 
;  byte 3: pointer to next entry in spare table which has been used in the
;          same LBA bit 16:10 block area.
; If LBA 9:0 of the current block match byte 1+2 of the "SpareTable" entry,
; this block has been replaced by the current spare.

SpareArray
SparePw1	DB 4 dup(?)		; fence (F0 78 3C 1E)
SpareTmStmp 	DB 4 dup(?)		; run number (incremented each time the spare table is written)
FmtOffset	DB 1 dup(?)		; format offset, default 0
FmtlntrL 	DB 1 dup(?)		; format (first) interleave set, default 1
SegPtrArray 	DB 128 dup(?)		; pointer (HeadPtr) to spares list for each LBA/0400h
SprCount	DB 1 dup(?)		; number of spares used
BadCount 	DB 1 dup(?)		; number of bad blocks pending
SpareBitMap 	DB 10 dup(?)		; bit set for each spare in use
SpareTable 	DB 76*4 dup(?)		; one entry per spare block
Map_Table	DB NbrSctrs dup(?)	; (second) interleave map
SpareCheck	DB 2 dup(?)		; checksum from fence to end of heap
SparePw2	DB 4 dup(?)		; fence (F0 78 3C 1E)
; 1A44
; Zone_Table	DB NbrTracks/NbrZones dup(?)

SpareLength 	EQU $-SpareArray
SpareEnd 	DB BlockLength-SpareLength dup(?)
Zone_Table	EQU SpareEnd		; ADC offset value for each group of 16 cylinders
BlockID 	EQU 512 		; fence (F0 78 3C 1E)



Abort_Stat 	DB 16 dup(?)		; (16D8h)  R0..15 of last aborted procedure


; >>> Cache
;
; The cache holds some information about the next 20 logical blocks: 
; whether a seek is needed, a head change is needed, or the way down
; through the spare table is necessary. This saves some time during
; multi-block commands.

CacheLength 	EQU NbrSctrs+1
CacheStat 	DB CacheLength dup(?)	; cached block's BlkStat
CacheArray 	DB 4*CacheLength dup(?)	; cached block's LBA


StackPtr 	DB 2 dup(?)		; (174Ch)
Heap 		EQU $

StartBlock 	EQU Heap
BlkOffset 	EQU StartBlock+3
Blklndex 	EQU BlkOffset+1

PBlock 		EQU Heap
TLBlock 	EQU PBlock+3
Cur_THS 	EQU TLBlock+3
PBlk            EQU Cur_THS+4

TopOfStack 	EQU 17FFh 		; top of external stack



;********************************************************************
;
; Servo Definitions
;
;********************************************************************

S_Cmnd_Byte 	EQU 000h	; Servo Command Byte
S_Diff_Byte 	EQU 001h	; Servo Lo Difference Byte
S_Off_Byte 	EQU 002h	; Servo Offset Byte
S_Stat_Byte 	EQU 003h	; Servo Status Byte

; BYTE 0  Command, Direction, and Hi Difference Byte
ReadStatus 	EQU 000h	; Servo Command: Read Status
Offset 		EQU 010h	; Servo Command: Offset, Track Following
Diagnostic 	EQU 020h	; Servo Command: Diagnostic
DataRecal 	EQU 040h	; Servo Command: Recalibrate heads, Data
FrmtRecal 	EQU 070h	; Servo Command: Recalibrate heads, Format
Access 		EQU 080h	; Servo Command: Access only
Access_Offset 	EQU 090h	; Servo Command: Seek with Offset
Home	 	EQU 0C0h	; Servo Command: Home the heads
;
Hd_Dir_Rev  	EQU 000h	; Direction: Reverse
Hd_Dir_Frwd  	EQU 004h	; Direction: Forward
;  Bits 0:1  Magnitude: Hi Difference

;  BYTE 1  Magnitude: Lo Difference

;  BYTE 2  Offset Byte
Off_Dir_Rev	EQU 000h	; Offset Direction Reverse
Off_Dir_Frwd 	EQU 080h	; Offset Direction Forward
Off_Auto 	EQU 040h	; Auto-Offset On
Ld_Off_Val 	EQU 020h	; Load Offset Value from DAC on Servo
Dir_Frwd	EQU 020h	; offset sign bit forward
;  Off_Val 	EQU 01Fh	; 5-bit value Loaded/Stored into DAC

;  BYTE 3  Status Byte
S_Rate_19_2 	EQU 000h 	; Servo/Controller baud rate = 19.2
S_Rate_57_6 	EQU 080h	; Servo/Controller baud rate = 57.6
Pwr_On_Reset 	EQU 040h	; Servo Power-On Reset
;
S_Stat_O 	EQU 000h	; Servo Status 0
S_Stat_1 	EQU 001h	; Servo Status 1
S_Stat_2 	EQU 002h	; Servo Status 2
S_Stat_3 	EQU 003h	; Servo Status 3
S_Stat_4 	EQU 004h	; Servo Status 4
S_Stat_5 	EQU 005h	; Servo Status 5
S_Stat_6 	EQU 006h	; Servo Status 6
S_Stat_7 	EQU 007h	; Servo Status 7

S_Norm_Status 	EQU S_Stat_1 	; Normal Servo Status



;********************************************************************
; 
; Z8 Internals
;
;********************************************************************

; Control Register 240 ($FO): Serial I/O register (SIO)
;              {Read: Receive Data}
;              {Write: Transmit Data}

; Control Register 241 ($F1): Timer Mode Register (TMR)
;   Tout Modes: Bits 7 and 6
T0_Out 		EQU 040h 	; Port 3, bit 6 gets timer 0 out
T1_Out 		EQU 080h 	; Port 3, bit 6 gets timer 1 out
Int_Out 	EQU 0C0h 	; Port 3, bit 6 gets system clock
; Tin Mode: Bits 5 and 4
Ext_Clk 	EQU 000h 	; use external clock on timer
Gate_Clk 	EQU 010h 	; use internal clock on timer
Non_Retrig 	EQU 020h 	; load T1 after a high-low trans
Retrig 		EQU 030h 	; like Non-Retrig, but load on all trans.
T1_CntEn 	EQU 008h 	; enable T1 counting operations
T1_CntDis 	EQU 000h
T1_Load 	EQU 004h 	; Load T1
T0_CntEn 	EQU 002h 	; enable T0 counting operations
T0_CntDis	EQU 000h
T0_Load		EQU 001h 	; Load T0

; Control Register 242 ($F2): Counter/Timer Register (T1)
;         {Write: Initial Value}
;         {Read: Current Count Value}

; Control Register 243 ($F3): T1 Prescaler Load Register (PRE1)
Single_Pass 	EQU 000h
Mod_n 		EQU 001h
T1_Int_Clk 	EQU 002h
T1_Ext_CIk 	EQU 000h
; Bits 7:2 are used to provide a 6-bit binary Prescale Value

; Control Register 244 ($F4): Counter/Timer Register (T0)
;         {Write: Initial Value}
;         {Read: Current Count Value}

; Control Register 245 ($F5): T0 Prescaler Load Register (PRE0)
;         {Same as Pre1, but no external clock}

; Control Register 246 ($F6): Port 2 Mode (P2M)
;  When a bit of P2M is set, the corresponding bit in Port 2 is defined
;  as an input, if reset then the corresponding bit for Port 2 is
;  defined as an output.

; Control Register 247 ($F7): Port 3 Mode (P3M)
Open_Drain 	EQU 000h
Totem_Pol 	EQU 001h
B2_5_Io 	EQU 000h	; Bit 2=input, Bit 5=output
B2_5_Hs 	EQU 004h 	; Bit 2=DAV0-, Bit 5=RDY0-
B3_4_Io 	EQU 000h	; Bit 3=input, Bit 4=output
B3_4_Idm 	EQU 010h 	; Bit 3=input, Bit 4=DM-
B3_4_Hs 	EQU 018h 	; Bit 3=DAV1-, Bit 4=RDY1-
B1_6_Io 	EQU 000h 	; Bit 1=Tin, Bit 6=Tout
B1_6_Hs 	EQU 020h 	; Bit 1=DAV2-, Bit 6=RDY2-_
B0_7_Io 	EQU 000h 	; Bit O=input; Bit 7=output
B0_7_Ser 	EQU 040h 	; Bit O=Sio in, Bit 7=Sio out
Par_On 		EQU 080h 	; Parity On
Par_Off 	EQU 000h 	; Parity Off

; Control Register 248 ($F8): Port 0 and 1 Mode (P01M)
P0_03_Out 	EQU 000h 	; select Port 0, bits 0:3 as outputs
P0_03_In 	EQU 001h 	; select Port 1, bits 0:3 as inputs
P0_03_Adr 	EQU 002h 	; select PO, bits 0:3 as adr bits 8:11
Stack_Ext 	EQU 000h 	; select external stack
Stack_In 	EQU 004h 	; select internal slack
P1_Out 		EQU 000h 	; select Port 1 as outputs
P1_In 		EQU 008h 	; select Port 1 as inputs
P1_Adr 		EQU 010h 	; select Port 1 as adr/data bits 0:7
P1_Tri 		EQU 018h 	; put port 1 into Tri-State
Mem_Ext 	EQU 020h 	; extended memory timing
Mem_Norm 	EQU 000h 	; normal memory timing
P0_47_Out 	EQU 000h 	; select Port 0, bits 4:7 as outputs
P0_47_In 	EQU 040h 	; select Port 0, bits 4:7 as inputs
P0_47_Adr 	EQU 080h 	; select PO, bits 4:7 as adr bits 12:15

; Control Register 249 ($F9): Interrupt Priority Register (IPR)
;              {To Be Established}

; Control Register 250 ($FA): Interrupt Request Register (IRQ)
; IRQ Definitions
Timer1		EQU 20h 	; Timer 1 interrupt
Timer0		EQU 10h 	; Timer 0 interrupt
Serial_Out	EQU 10h 	; Sio transmitter ready
Serial_In	EQU 08h 	; Sio receiver ready
Irq_Sector	EQU 04h 	; Negative edge on sector mark
Irq_SecDn	EQU 02h
Irq_Index	EQU 01h 	; Negative edge on index mark


; Control Register 251 ($FB): Interrupt Mask Register (IMR)
;              {To Be Established}

; Control Register 252 ($FC): Flag Register (FLAGS)
;              {To Be Established}

		restore


