; commented disassembly of HP9121 firmware ; commented 2012 by Holger Veit ; provided as is under Creative Commons License CC-BY-SA ; http://creativecommons.org/licenses/by-sa/3.0/ ; ; No warranty is given that documented information is ; completely correct; the author (who commented it) ; is not responsible for any damage resulting from the ; use of this information. ; ; Note: this might look like valid assembler but might not work at all. ; This is only for documentation, and not intended to be usable ; for producing binaries or ROMs. ;============================================= ; some structures ;============================================= ; CPU 6809 status register cc_c: equ 1 cc_v: equ 10b cc_z: equ 100b cc_n: equ 1000b cc_irq: equ 10000b cc_h: equ 100000b cc_firq: equ 1000000b cc_e: equ 10000000b ;============================================= ; FDC controller, refer to datasheet ; note FDC has inverted data bus, i.e. everything read or written ; needs to be complemented (negative logic) MB8876 struc str_cr: .db ? ; command register / status register tr: .db ? ; track register scr: .db ? ; sector register dr: .db ? ; data register MB8876 ends ; FDC commands (negative logic) fdcmd_restore equ ~0x0B fdcmd_seek equ ~0x1B fdcmd_writesec equ ~0x57 fdcmd_stepin equ ~0x5B fdcmd_stepout equ ~0x7B fdcmd_readsec equ ~0x88 fdcmd_writesec1 equ ~0xA8 fdcmd_readaddr equ ~0xC0 fdcmd_forceint equ ~0xD0 fdcmd_writetrk equ ~0xF0 ; fdc_status1 flags fdc_status1_busy: equ 1 fdc_status1_index: equ 10b fdc_status1_trk0: equ 100b fdc_status1_crcerror: equ 1000b fdc_status1_seekerror: equ 10000b fdc_status1_headload: equ 100000b fdc_status1_wrtprot: equ 1000000b fdc_status1_notready: equ 10000000b ; fdc_status23 flags fdc_status23_busy: equ 1 fdc_status23_drq: equ 10b fdc_status23_lostdata: equ 100b fdc_status23_crcerror: equ 1000b fdc_status23_recnf: equ 10000b fdc_status23_wrtflt: equ 100000b fdc_status23_wrtprot: equ 1000000b fdc_status23_notready: equ 10000000b ;============================================= ; GPIB controller; refer to data sheet GPIB8291 struc dataio: .db ? ; data in/out intreg1: .db ? ; int status / enable intreg2: .db ? ; int status /enable serpoll: .db ? ; serial poll status / enable addrreg: .db ? ; address status / mode cmdauxreg: .db ? ; cmd pass thru / aux mode addr0_01: .db ? ; address 0 / 01 addr1_eos: .db ? ; address 1 / eos GPIB8291 ends ; GPIB INT1 Status flags ints1_bi: equ 1 ints1_bo: equ 10b ints1_err: equ 100b ints1_dec: equ 1000b ints1_end: equ 10000b ints1_get: equ 100000b ints1_apt: equ 1000000b ints1_cpt: equ 10000000b ; GPIB INT1 enable inte1_bi: equ 1 inte1_bo: equ 10b inte1_err: equ 100b inte1_dec: equ 1000b inte1_end: equ 10000b inte1_get: equ 100000b inte1_apt: equ 1000000b inte1_cpt: equ 10000000b ; GPIB INT2 status flags ints2_adsc: equ 1 ints2_remc: equ 10b ints2_lloc: equ 100b ints2_spc: equ 1000b ints2_rem: equ 10000b ints2_llo: equ 100000b ints2_spas: equ 1000000b ints2_int: equ 10000000b ; GPIB INT2 enable inte2_adsc: equ 1 inte2_remc: equ 10b inte2_lloc: equ 100b inte2_spc: equ 1000b inte2_dmai: equ 10000b inte2_dmao: equ 100000b ; GPIB SPS flags (not used) sps_s1: equ 1 sps_s2: equ 10b sps_s3: equ 100b sps_s4: equ 1000b sps_s5: equ 10000b sps_s6: equ 100000b sps_rsv: equ 1000000b sps_s8: equ 10000000b ; GPIB SP enable (not used) spe_s1: equ 1 spe_s2: equ 10b spe_s3: equ 100b spe_s4: equ 1000b spe_s5: equ 10000b spe_s6: equ 100000b spe_rsv: equ 1000000b spe_s8: equ 10000000b ; GPIB Address status as_mjmn: equ 1 as_ta: equ 10b as_la: equ 100b as_tpas: equ 1000b as_lpas: equ 10000b as_eoi: equ 100000b as_lon: equ 1000000b as_ton: equ 10000000b ; GPIB address mode am_adm0: equ 1 am_adm1: equ 10b am_lo: equ 1000000b am_to: equ 10000000b ; GPIB AD 0 flags ad0_ad10: equ 1 ad0_ad20: equ 10b ad0_ad30: equ 100b ad0_ad40: equ 1000b ad0_ad50: equ 10000b ad0_dl0: equ 100000b ad0_dt0: equ 1000000b ad0_int: equ 10000000b ; GPIB AD0/1 flags ad01_ad1: equ 1 ad01_ad2: equ 10b ad01_ad3: equ 100b ad01_ad4: equ 1000b ad01_ad5: equ 10000b ad01_dl: equ 100000b ad01_dt: equ 1000000b ad01_ars: equ 10000000b ; GPIB AUXM commands auxm_imm_pon: equ 0 auxm_clr_pp: equ 1 auxm_reset: equ 2 auxm_finhs: equ 3 auxm_trigger: equ 4 auxm_clr_rtl: equ 5 auxm_sendeoi: equ 6 auxm_nv_sa: equ 7 auxm_pon: equ 8 auxm_set_pp: equ 9 auxm_set_rtl: equ 0xD auxm_v_sa: equ 0xF ; GPIB AD1 flags ad1_ad11: equ 1 ad1_ad21: equ 10b ad1_ad31: equ 100b ad1_ad41: equ 1000b ad1_ad51: equ 10000b ad1_dl1: equ 100000b ad1_dt1: equ 1000000b ad1_x: equ 10000000b ;============================================= ; Bits of CTRL Port ctrl_sidesel: equ 1 ctrl_motor: equ 10b ctrl_hdld: equ 100b ctrl_clridx: equ 1000b ctrl_drsel1: equ 10000b ctrl_drsel0: equ 100000b ctrl_led: equ 1000000b ctrl_halten: equ 10000000b ;============================================= ; Bits of STATUS port status_addrsw0: equ 1 status_addrsw1: equ 10b status_addrsw2: equ 100b status_drwpt: equ 1000b status_test: equ 10000b status_dualhead: equ 100000b status_loop: equ 1000000b status_drrdy: equ 10000000b ;============================================= ; Status S1 of Amigo command set, see documentation amigo_s1_normal: equ 0 amigo_s1_illop: equ 1 amigo_s1_cylcmp_err: equ 7 amigo_s1_data_err: equ 8 amigo_s1_seccmp_err: equ 9 amigo_s1_ioprog_err: equ 0xA amigo_s1_dbitset: equ 0x11 amigo_s1_rtry_hw_err: equ 0x12 amigo_s1_status2_err: equ 0x13 amigo_s1_unitunavail: equ 0x17 amigo_s1_drvatt: equ 0x1F ; Status S2 of Amigo command set amigo_s2_driveready: equ 0 amigo_s2_drivenotready: equ 3 amigo_s2_seekcheck: equ 4 amigo_s2_firststatus: equ 8 amigo_s2_drvfault: equ 0x10 amigo_s2_wrtprotect: equ 0x40 amigo_s2_attention: equ 0x80 ;============================================= ; some direct page register definitions ; note DP register is set to 0x40, thus denoting ; GPIB address space 0x4000-0x4007 gpio_dio: equ 0 gpib_int1: equ 1 gpib_int2: equ 2 gpib_spm: equ 3 gpib_am: equ 4 gpib_auxm: equ 5 gpib_ad01: equ 6 gpib_ad1: equ 7 ;============================================= ; RAM 1K at 0x0000 ; variables tagged with UNIT exist for at most 4 drives ; in HP9121D, only two are in use ; The cylinder/track/head mess: ; Unfortunately, I have used track and cylinder interchangedly ; when trying to decode the ROM. The real situation is as follows: ; the drive is single sided with 70 tracks. For amigo compatibility, ; it is addressed as if it were a 35 track dual head drive. The ; FDC TR register counts actual drive tracks (70). The even tracks ; are assumed to be head 0, the odd ones are head 1, and they are ; likewise formatted, i.e. the 2nd physical track has TRK# 0 and HEAD 1 ; coded in. To calculate phys track from amigo convention, just double trk# ; and add head number. This happens several times in the code. ; sector format: a track contains 16 sectors of 256 bytes, numbered 0 to 15 ; and a 17th sector with sector number 17 of 128 bytes. ; The only information in sector 17 are the first three bytes, which keep the ; "wear level information". This tries to count the number of revolutions and ; steppings of a disk, and is an indication of usage. The following three bytes ; in the sector differ for a newly formatted and already used disk. See the ; formatting rountine and the write_sector17 routine. The other 122 bytes ; of this sector are entirely unused. org 0 diskbuf .ds 256 end_buf: .ds 1 status_s1: .ds 1 ; status S1 from amigo_readstatus status_s1_unit: .ds 1 ; unit of status S1 status_s2_type: .ds 1 ; type of status S2 status_s2_flags: .ds 1 ; disk flags of status S2 sys_state: .ds 1 ; internal system state (mainly set, not really used) portctrl_state: .ds 1 ; readable value of CTRL port (which HW is write only) format_track: .ds 1 ; flag for amigo_initalize (listen 00 will do formatting) has_sec17: .ds 1 ; flag that we have data from sector 17 drvN_endofdisk: .ds 4 ;UNIT flag that unbuffered R/W reached end of disk drvN_inactive: .ds 4 ;UNIT flag that drive is in inactive (power save) mode motoron_flg: .ds 1 ; flag that drive motor is spinning fdc_headisloaded: .ds 1 ; flag that drive head is loaded unbufread_flg: .ds 1 ; flag to signal multi-sector read ("unbuffered read") unbufwrite_flg: .ds 1 ; flag to signal multi-sector write ("unbuffered write") eoi_flag: .ds 1 ; flag to send next byte with EOI gpib_apt_flag: .ds 1 ; flag to signal that a verify secondary interrupt was seen drive_ptr: .ds 2 ; holds 16bit 0/1 to address currently active UNIT flags (U register) drvN_tgthead: .ds 4 ;UNIT hold the target head to be positioned to drvN_tgtcylinder: .ds 4 ;UNIT hold target track to be positioned to drvN_tgtsector: .ds 4 ;UNIT hold target sector to be read/written next drvN_activehead: .ds 4 ;UNIT currently active head selected drvN_activecyl: .ds 4 ;UNIT currently active cylinder selected drvN_curhead: .ds 4 ;UNIT currently read head from disk drvN_curtrk: .ds 4 ;UNIT currently read trak from disk drvN_storecyl: .ds 4 ;UNIT holds addressed cylinder when drive is inactive drvN_storehead: .ds 4 ;UNIT holds addressed head when drive is inactive drvN_savedtrk: .ds 4 ;UNIT holds addressed cylinder when drive is inactive drvN_savedhead: .ds 4 ;UNIT holds addressed head when drive is inactive .ds 4 ; unused s1_errcode: .ds 1 ; S1 completion code of operations .ds 1 ; unused selected_unit: .ds 1 ; currently addressed UNIT (8 bit value of drive_ptr) drvN_disktype: .ds 4 ;UNIT disk type drvN_s2flags: .ds 4 ;UNIT last S2 status of disk dsj: .ds 1 ; DSJ byte (see documentation) drvN_disk_wornout: .ds 2 ;UNIT signal that disk might be no longer reliable and might need reforming drv_softwrtprotect:.ds 2 ; preventive protection of disk due to errors selftest_1 .ds 1 ; selftest status 1 selftest_2 .ds 1 ; selftest status 2 override_old_fmt: .ds 1 ; override old format flag for formatting format_interleave: .ds 1 ; interleave for format format_head: .ds 1 ; head to format format_cylinder: .ds 1 ; cylinder to format format_filler: .ds 1 ; data fill byte for format curtrk: .ds 1 ; current track as read from drive curhead: .ds 1 ; current head as read from drive verify_seccnt: .ds 2 ; 16bit counter for disk verify seek_retrycnt: .ds 1 ; counter for SEEK retry drvstatus_retrycnt: .ds 1 ; counter for get disk status retry fdc_status: .ds 1 ; FDC status returned from controller ; (except bit 0,1,5, bit 7 is drive ready) ; also used as temporary temp3 .ds 1 ; temporary save trkpattern: .ds 2 ; used in writedisk for formatting pattern index tempx2 .ds 2 ; temporary X save tempx: .ds 2 ; temporary X save dummy_buffer: .ds 1 ; used in DRQ/HALTEN logic to reset DRQ cycle when ; nothing else addresses RAM temp1: .ds 1 ; temporary save format_tgtcylinder: .ds 1 ; used in format, also temporary temp4 .ds 2 ; temporary save drvN_irqwearh: .ds 4 ;UNIT counter for revolutions, set by INT on index pulse drvN_irqwearm: .ds 4 drvN_irqwearl: .ds 4 drvN_wearh: .ds 4 ;UNIT disk wear counters read from sector 17 drvN_wearm: .ds 4 drvN_wearl: .ds 4 drvN_updatewear: .ds 4 ;UNIT flag to indicate that wear counters need to be written back to sector 17 drvN_selectmask: .ds 4 ;UNIT drive selection mask saveu: .ds 2 ; used to store U register when another drive is to be selected than the one ; amigo expects, e.g. in checking disk wear level format_specinterleave: .ds 1 ; temporary holds interleave in diskwrite fmtcnt: .ds 1 ; counter used in formatter sector_numbers: .ds 0x10 ; holds interleave table of sector numbers cnt16: .ds 2 ; 16bit counter used in interleave setting drive_cnt: .ds 1 ; used as disk marker in disk reforming byte_1AA: .ds 1 ; just written, never read drv_stepdelta: .ds 1 ; hold delta of steps between current and requested head position readwear_retrycnt: .ds 1 ; retry counter for obtaining sector17 information downloadbuf: .ds 256 ; 256 byte code buffer for download command .ds 325 ; unused chkram_top: .ds 1 ; top area to be checked by RAM selftest .ds 12 ; stack area stacktop: .ds 1 ; initialization value of stack pointer ;============================================================ ; FDC address space .org 0x2000 FDC_port: .ds 1 ; structure: str_cr .ds 1 ; tr .ds 1 ; scr .ds 1 ; dr .ds 8188 ; incomplete decoding, repeated ;============================================================ ; GPIB address space ; Note: not addressed directly, rather by zero ; page DP=0x40 .org 0x4000 .ds 8 ; structure GPIB .ds 8184 ; incomplete decoding, repeated ;============================================================ ; control (writeonly) and status port (readonly .org 0x6000 portcc .ds 1 statuscc equ portcc .ds 0x8191 ; incomplete decoding, repeated ;============================================================ ; ROM starts here .org 0xE000 reset_vector: lds #stacktop ; load stack top jsr selftest_chk_ram ; test if RAM is okay bcs fatal_error ; not okay jsr selftest_chk_rom ; test if ROM checksum is okay bcs fatal_error ; not okay jsr selftest_chk_fdc ; test if FDC is present and TR and SCR regs are writeable bcs selftest_fdc_chip_error ; not okay, set error code ldb #5 ; constant 5 (confidence test passed) jsr blink_led ; blink 5 times bra initialize_all ; cannot continue here on reset fatal_error: lda #ctrl_led ; enable LED sta portcc ; into port sta portctrl_state ; into state save loc_E022: bra loc_E022 ; endless loop ;============================================= rom_checksum: .dw 0x5110 selftest_fdc_chip_error: lda #0x88 ; error code 10001000 (Error bit set) sta selftest_2 lda #9 ; FDC error 0100 sta selftest_1 lda portctrl_state ; get ctrl state oraa #ctrl_led ; set LED on oraa #ctrl_clridx ; set CLRINDEX bit sta portctrl_state sta portcc ;============================================= initialize_all: lda #0x40 ; select HPIB through direct page tfr a, dp jsr init_gpib ; initialize 8291 lda #2 sta dsj ; init flag? lda statuscc ; check dual head operation bita #status_dualhead bne loc_E05C ; no is single head lda #0x21 ; dualhead flag 1 sta drvN_selectmask+2 lda #0x11 ; dualhead flag 2 sta drvN_selectmask+3 bra device_clear loc_E05C: lda #0 ; clear dual head flags sta drvN_selectmask+2 lda #0 sta drvN_selectmask+3 ;============================================= device_clear: ldx #end_buf ; start of ram to clear clra loc_E06A: sta ,x+ ; clear it and advance cmpx #dsj ; until (excluding) DSJ bne loc_E06A ; loop jsr fdc_restore_all_drives ; position all drives to track 0 jsr delay_5000 ; wait lda portctrl_state ; get port state oraa #ctrl_clridx ; set CLRINDEX bit sta portctrl_state ; store it sta portcc ; into port as well lda dsj ; get DSJ byte cmpa #2 bne loc_E092 ; not just initialized jsr fdc_spinup ; start motor jsr gpib_set_PP ; set parallel poll jmp mainloop ; main loop loc_E092: jsr gpib_set_PP ; set parallel poll jsr park_heads_at_17 ; position heads at trk 17 jmp mainloop ; normal processing ;============================================= ; blink LED B times blink_led: aslb ; multiply B with 2 (on & off) loc_E09C: ldy #62500 ; delay value loc_E0A0: leay -1,y ; long delay bne loc_E0A0 lda #ctrl_led ; ctrl LED bit eora portctrl_state ; toggle CTRL reg state sta portcc ; store ctrl reg sta portctrl_state decb ; decrement blink loop bne loc_E09C ; loop rts ;============================================= led_on: lda portctrl_state ; get ctrl state oraa #ctrl_led ; set LED on sta portctrl_state ; store state sta portcc ; set CTRL port rts ;============================================= led_off: lda portctrl_state ; get ctrl state anda #~ctrl_led ; switch off LED sta portctrl_state ; store status sta portcc ; set ctrl port rts ;============================================= ; initialize GPIB controller ; DP points to GPIB init_gpib: lda #auxm_reset ; issue Chip reset sta gpib_auxm ; initialize GPIB lda #inte1_bi|inte1_bo|inte1_dec|inte1_apt sta gpib_int1 ; enable BI, BO, DCAS, APT interrupts clrb ; clear int enable 2 stb gpib_int2 ; also disable DMA operation stb gpib_spm ; no serial poll bits lda #am_adm0|am_adm1 sta gpib_am ; set address mode 3 (extended talker/talker with APT check) lda statuscc ; get address switches anda #status_addrsw0|status_addrsw1|status_addrsw2 sta gpib_ad01 ; set as major primary address (0-7) lda #ad01_ad1|ad01_ad2|ad01_ad3|ad01_ad4|ad01_ad5|ad01_dl|ad01_ars sta gpib_ad01 ; set minor address 31, listener only lda #0x22 ; preset internal counter to 2MHz sta gpib_auxm lda #0x80 ; no special AuxA bits sta gpib_auxm lda #0xA8 ; AuxB: enable active low interrupt sta gpib_auxm stb gpib_auxm ; send immediate pon lda gpib_ad01 ; read address 0 coma ; complement address anda #7 ; mask out bits 0-2 oraa #0x68 ; enable serial poll, bit 7-addr, sense 1 sta gpib_auxm lda gpio_dio ; actually read gpib_dio rts ;============================================= ; DRQ/Int logic: ; HaltEN=0: ; never halt processor ; ignore +DRQ ; ignore +FDCInt ; FIRQ=0 if HPIBInt=0 ; HaltEn=1 ; halt processor if RAM or GPIB chip select (rising edge) ; release processor if DRQ=1 or FIRQ=0 ; FIRQ=0 if DrRdy=0 or HPIBInt=0 or FDCInt=1 ; handles GPIB Int / DRQ processing firq_vector: leas 3,s ; drop CC, PC, won't ever return from FIRQ ; but return to caller saved on stack lda portctrl_state ; get ctrl port state anda #~ctrl_halten ; set HALTEN = 0 (will release FIRQ) sta portctrl_state ; set ctrl sta portcc lda sys_state ; positive state? bpl firq_process_fdc ; yes, this is processing of FDC / DRQ logic ldb gpib_ad01 ; read GPIB interrupt status bpl loc_E12E ; INT flag not set? skip ; FIRQ was asserted by HPIBInt ; won't return to caller lds #stacktop ; reset stack pointer ldu saveu ; get saved U (drive selected by amigo) stu drive_ptr ; current drive ldb #inte1_bi|inte1_bo|inte1_dec|inte1_apt stb gpib_int1 ; reenable interrupts clr sys_state ; clear state jsr fdc_select_curdrv ; select correct drive jmp gpib_handle_int ; handle GPIB interrupt ; FIRQ was asserted by FDCInt or DrRdy loc_E12E: ldb statuscc ; get drive ready flag bpl firq_process_fdc ; DrRdy became 1? ldu saveu ; no, FIRQ because drv no longer ready stu drive_ptr ; reload drive in operation ldb #inte1_bi|inte1_bo|inte1_dec|inte1_apt stb gpib_int1 ; enable GPIB interrupts again clr sys_state ; clear state jsr fdc_select_curdrv ; select current drive bra loc_E14D ; return status ; this is called when a FDCINT is sent from FDC ; logic: disable GPIBINT, set HALTEN=1, ; and do a single read of RAM ; CPU halts until DRQ becomes 1; if so, it continues, ; e.g. by processing FDC DR ; at the end of operation FDCInt is generated and ; will trigger this code in FIRQ firq_process_fdc: anda #0x7F ; mask low bits of state cmpa #4 ; is fdc state > 4? lbge gpib_errorstate ; yes, invalid state for FDC processing loc_E14D: lda FDC_port.str_cr ; get FDC control reg coma ; complement (negative bus) ; mask error bits anda #fdc_status23_lostdata|fdc_status23_crcerror|fdc_status23_recnf|fdc_status23_wrtprot sta fdc_status ; save status lda statuscc ; get drive status anda #status_drrdy ; mask highest bit oraa fdc_status ; put into error bits sta fdc_status ; save status jsr fdc_terminate_no_int ; terminate current FDC command lda #inte1_bi|inte1_bo|inte1_dec|inte1_apt sta gpib_int1 ; reinitialize GPIB interrupt sources lda fdc_status rts ; tricky code: fall back into routine that issued the FDC operation ; so DRQ transfers need to be called in a subroutine ;============================================= ; advance to the next sector on disk ; return CY=1 if at end of disk fdc_nextsector: inc drvN_tgtsector,u ; increment sector count lda drvN_tgtsector,u ; is sector < 16? cmpa #16 bne loc_E1A3 ; no, exit CY=0 fdc_nextsector1: clr drvN_tgtsector,u ; set new sector=0 tst drvN_tgthead,u ; check head bne loc_E18A ; is 1, toggle to 0 lda #1 ; was 0, set head=1 sta drvN_tgthead,u bra loc_E1A3 ; exit CY=0 loc_E18A: clr drvN_tgthead,u ; set head=0 inc drvN_tgtcylinder,u ; increment cylinder lda drvN_tgtcylinder,u ; get cylinder cmpa #35 ; is it 35? bne loc_E1A3 ; no, exit CY=0 lda #1 ; notify: at end of disk sta drvN_endofdisk,u orcc #cc_c ; return CY=1 rts loc_E1A3: andcc #~cc_c ; clear CY clr drvN_endofdisk,u ; not at end of disk rts ;============================================= fdc_movetrack_in: lda drvN_curhead,u ; is head=1 bne loc_E1BB ; yes, skip lda #1 ; select head 1 sta drvN_curhead,u ; store it jsr fdc_stepin ; do a single step bra loc_E1D9 ; exit with CY=0 loc_E1BB: clr drvN_curhead,u inc drvN_curtrk,u ; increment current track lda drvN_curtrk,u ; get it cmpa #35 ; is last track reached? bne loc_E1D6 ; no, do a step dec drvN_curtrk,u ; remain at last track inc drvN_curhead,u orcc #cc_c ; exit with CY=1 rts loc_E1D6: jsr fdc_stepin ; do a step loc_E1D9: andcc #~cc_c ; exit with CY=0 rts ;============================================= fdc_movetrack_out: lda drvN_curhead,u ; is head 0? beq loc_E1EB ; yes, toggle 0 1 clr drvN_curhead,u ; no, set to 0 jsr fdc_stepout ; step out and issue interrupt bra loc_E20A ; exit with CY=0 loc_E1EB: inc drvN_curhead,u ; set head=1 dec drvN_curtrk,u ; decrement current track lda drvN_curtrk,u ; get current track bpl loc_E207 ; not yet at track 0, skip clr drvN_curtrk,u ; was at track 0, set currtrk=0 clr drvN_curhead,u ; and curhead=0 jsr fdc_stepout ; step out and issue interrupt orcc #cc_c ; exit with CY=1 rts loc_E207: jsr fdc_stepout ; do step out loc_E20A: andcc #~cc_c ; clear CY rts ;============================================= ; start motor fdc_spinup: lda portctrl_state ; get ctrl port bita #ctrl_motor ; is motor already on? bne loc_E22C ; yes, skip oraa #ctrl_motor ; set motor on sta portctrl_state ; set state sta portcc ldx #55295 ; long delay (about 1 second) loc_E21F: jsr nullsub_1 ; wait jsr nullsub_1 ; wait leax -1,x bne loc_E21F ; delay loop jsr fdc_loadhead ; load drive head loc_E22C: lda #1 ; set flag motor on sta motoron_flg nullsub_1: rts ;============================================= ; switch off drive motor fdc_motoroff: jsr fdc_unloadhead lda portctrl_state ; get port state anda #~ctrl_motor sta portctrl_state ; motor off sta portcc clr motoron_flg ; signal motor off orcc #cc_irq ; disable IRQ rts ;============================================= ; wait until FDC ready and select current drive (specified by drive_ptr) fdc_waitrdy_select_curdrv: jsr fdc_waitrdy ; wait until FDC is ready ;============================================= ; select current drive (specified by drive_ptr) fdc_select_curdrv: pshs a,b ; save A,B ldb drive_ptr+1 ; get drive # (0-3) andb #3 ; mask out drive# cmpb #0 ; is drive 0? bne loc_E258 ; no, skip lda #ctrl_drsel0 ; bitmask for drive 0 bra loc_E26C loc_E258: cmpb #1 ; is drive 1? bne loc_E260 ; no, skip lda #ctrl_drsel1 ; bitmask for drive 1 bra loc_E26C loc_E260: cmpb #2 ; is drive 2? bne loc_E269 ; no, skip lda drvN_selectmask+2 ; get mask for drive 2 bra loc_E26C loc_E269: lda drvN_selectmask+3 ; get mask for drive 3 loc_E26C: ldb portctrl_state ; get ctrl port andb #ctrl_sidesel|ctrl_drsel1|ctrl_drsel0 stb temp1 ; save last selected drive/surface cmpa temp1 ; same as requested? beq loc_E2AC ; yes, skip ldb portctrl_state ; get ctrl port bitb #ctrl_hdld ; is head loaded? beq loc_E298 ; no, skip andb #~ctrl_hdld ; unload head stb portctrl_state stb portcc ; set to port clr fdc_headisloaded ; clear headload flag stx tempx2 ; save X ldx #0x100 ; delay for unload head loc_E291: leax -1,x bne loc_E291 ; loop ldx tempx2 ; restore X loc_E298: ldb portctrl_state ; get state andb #~ctrl_sidesel|ctrl_drsel1|ctrl_drsel0 ; mask out drive bits stb portcc ; store state stb portctrl_state oraa portctrl_state ; put in requested drive bits sta portctrl_state sta portcc ; set ctrl port loc_E2AC: lda drvN_inactive,u ; is drive active? beq loc_E2BD ; yes, skip lda drvN_storecyl,u ; get stored position asla ; *2 adda drvN_storehead,u ; add head bra loc_E2C6 ; put into track register loc_E2BD: lda drvN_activecyl,u ; get the current position asla ; *2 adda drvN_activehead,u ; + head loc_E2C6: coma ; negative logic sta FDC_port.tr ; set track puls b,a rts ;============================================= ; select drive 0, side 0 fdc_select_drv0: ldy #0x100 ; small delay loc_E2D1: ; ... leay -1,y bne loc_E2D1 ; loop lda portctrl_state ; get ctrl port anda #~ctrl_sidesel|ctrl_drsel1|ctrl_drsel0 sta portctrl_state ; drsel 0, drsel 1, drsidesel sta portcc ; set drive 0, side 0 rts ;============================================= ; wait until FDC is no longer busy fdc_waitrdy: pshs a ; save A stx tempx ; save X ldx #2 ; init long delay counter 0x00020000 ldy #0 loc_E2ED: jsr nullsub_2 ; wait lda FDC_port.str_cr ; get FDC status bita #fdc_status1_busy ; is busy? bne loc_E302 ; not busy (negative logic!), exit leay -1,y ; wait bne loc_E2ED leax -1,x bne loc_E2ED ; timing loop ended without command done jsr fdc_terminate_no_int ; terminate with no interrupt loc_E302: puls a ; restore A, X, exit ldx tempx nullsub_2: rts ;============================================= ; send force no-int command to terminate pending operation fdc_terminate_no_int: lda #fdcmd_forceint ; force interrupt (terminate with no interrupt) sta FDC_port.str_cr ; set command jsr fdc_waitrdy ; wait until done rts ;============================================= ; return drive status in A, negative if drive not ready ; set cur_trk (physical) and cur_side fdc_getdrvstatus: lda #4 sta drvstatus_retrycnt ; try 4 times loc_E316: jsr fdc_readaddress_status ; get status of drive beq loc_E322 ; is zero: drive ready and no error bmi loc_E322 ; is negative: drive not ready dec drvstatus_retrycnt ; drive is ready, and error bits were set bne loc_E316 ; retry 4 times loc_E322: lda curtrk ; get current track bmi loc_E334 ; negative, return status asr curtrk ; convert logical track to physical bcc loc_E334 ; if LSBit was 1, set side bit lda curhead oraa #1 ; odd number of logical track is on side 1 ; even is on side 0 sta curhead loc_E334: lda fdc_status ; get fdc status rts ; return to caller ;============================================= ; issue a READADDR to get track# and side# and the FDC status bits ; interacts with FIRQ code which returns to the caller. Thus, no endless loop fdc_readaddress_status: lda sys_state ; get system state anda #0x80 ; mask bit 7 oraa #3 ; set state 3 sta sys_state lda FDC_port.str_cr ; read FDC status to acknowledge clra sta gpib_int1 ; disable GPIB interrupts tst fdc_headisloaded ; check whether head is loaded bne loc_E350 ; no, load it jsr fdc_loadhead ; load head loc_E350: andcc #~cc_firq ; enable FIRQ lda portctrl_state oraa #ctrl_halten ; set HALTEN sta portctrl_state sta portcc ; thus, allow FDCInt to occur if drive is ready ldb #fdcmd_readaddr ; FDC READ ADDRESS command ; will return 6 bytes in DR: ; 1 track address ; 2 side number ; 3 sector address (ignored) ; 4 sector length (ignored) ; 5 CRC1 (ignored) ; 6 CRC2 (ignored) stb FDC_port.str_cr lda dummy_buffer ; dummy instruction: trigger HALT-FF nop ; DRQ releases CPU nop ; dummy lda FDC_port.dr ; read the 1st byte coma sta curtrk ; save it, trigger HALT-FF nop ; DRQ releases CPU nop ; dummy lda FDC_port.dr ; read 2nd byte coma sta curhead ; save it, trigger HALT-FF loc_E377: lda FDC_port.dr ; DRQ releases CPU, read 3rd-6th byte nop nop lda dummy_buffer ; trigger HALT-FF bra loc_E377 ; DRQ releases CPU, loop until FIRQ stops this loop and ; returns to caller with FDC flags ;============================================= ; load drive head if drive ready fdc_loadhead: lda statuscc ; get status port bmi locret_E39E ; not drive ready, exit ; drive is ready, and contains a disk lda portctrl_state oraa #ctrl_hdld ; load head sta portctrl_state sta portcc lda #1 ; set flag head load sta fdc_headisloaded ldy #15000 ; delay loc_E39A: leay -1,y bne loc_E39A ; wait for head load locret_E39E: rts ;============================================= ; unload drive head fdc_unloadhead: lda portctrl_state ; get ctrl state anda #~ctrl_hdld sta portctrl_state ; unload head sta portcc clr fdc_headisloaded ; clear flag head load stx tempx2 ; save x ldx #0x100 ; small delay loc_E3B3: leax -1,x bne loc_E3B3 ; loop ldx tempx2 ; restore x rts ;============================================= ; do a step in (towards trk 69) fdc_stepin: pshs a ; save A lda #fdcmd_stepin ; issue STEPIN command, update track reg, load head sta FDC_port.str_cr ; send command jsr fdc_waitrdy ; wait until ready puls a ; restore A rts ;============================================= ; do a step out (towards trk0) fdc_stepout: pshs a ; save A lda #fdcmd_stepout ; issue STEP OUT cmd, update track reg, load head sta FDC_port.str_cr jsr fdc_waitrdy ; wait until command done puls a ; restore A rts ;============================================= ; position head to track 0 ; return CY=1 if failure, 0 if success fdc_restore_trk0: lda #fdcmd_restore ; Restore command sta FDC_port.str_cr ; set command jsr fdc_waitrdy ; wait until done lda FDC_port.str_cr bita #fdc_status1_trk0 ; track0 reached? beq loc_E3E7 ; yes, skip orcc #cc_c ; set CY=1 (failure) rts loc_E3E7: lda #~0 ; set track register = 0 sta FDC_port.tr clra sta drvN_activecyl,u ; clear active position sta drvN_activehead,u sta drvN_curtrk,u ; clear current position sta drvN_curhead,u sta drvN_endofdisk,u ; clear end of disk flag andcc #~cc_c ; set CY=0 (success) rts ;============================================= ; position both drives to track 0 fdc_restore_all_drives: lda #1 ; select drive 1 sta drive_ptr+1 ; note driveptr+0 was initialized to 0 loc_E409: ldu drive_ptr ; get ptr to drive parameters jsr fdc_waitrdy_select_curdrv ; select the correct drive jsr fdc_restore_trk0 ; goto track 0 dec drive_ptr+1 ; point to drive 0 bpl loc_E409 ; loop for drives clr drive_ptr+1 ; select drive 0 ldu drive_ptr ; get current drive ptr rts ;============================================= fdc_seek: lda #5 ; set seek retry count sta seek_retrycnt lda drvN_inactive,u ; is drive inactive? beq loc_E43D ; no, skip clr drvN_inactive,u ; is now active lda drvN_storecyl,u ; copy parameters sta drvN_activecyl,u lda drvN_storehead,u sta drvN_activehead,u loc_E43D: lda drvN_tgtcylinder,u ; target to reach cmpa drvN_activecyl,u ; is position reached? bne seek_reposition ; no, reposition lda drvN_tgthead,u ; is the right head selected? cmpa drvN_activehead,u bne seek_reposition ; no, reposition jmp loc_E4D7 ; yes, seems we are done seek_reposition: lda drvN_curtrk,u ; get current track asla ; shift left adda drvN_curhead,u ; insert head coma ; negative logic sta FDC_port.tr ; store in fdc track register ldb drvN_tgtcylinder,u ; get target to reach subb drvN_activecyl,u ; subtract current position aslb ; shift left addb drvN_tgthead,u ; add target head subb drvN_activehead,u ; subtract current head stb drv_stepdelta ; store number of steps to do tstb ; is it zero? beq loc_E4BB ; yes, positioned right tfr b, a ; put delta into A bpl loc_E47D ; positive? coma ; no, complement ; set positive number of steps to do loc_E47D: lsra ; add steps/4 to current wear count lsra adda drvN_irqwearl,u sta drvN_irqwearl,u bcc loc_E493 inc drvN_irqwearm,u bne loc_E493 inc drvN_irqwearh,u loc_E493: lda FDC_port.tr ; get track register (current pos) coma ; negative logic pshs b ; save delta adda ,s+ ; pop and add to track sta temp1 ; save it in temporary (position to reach) anda #1 ; mask out head sta drvN_curhead,u ; save into current head lda temp1 ; get position lsra ; discard head sta drvN_curtrk,u ; save in current track lda temp1 ; get position to reach coma ; negative logic sta FDC_port.dr ; position to reach in data register lda #fdcmd_seek ; issue SEEK command to FDC sta FDC_port.str_cr jsr fdc_waitrdy ; wait until done loc_E4BB: lda drvN_tgtcylinder,u ; copy target into active cylinder sta drvN_activecyl,u asla ; shift left adda drvN_tgthead,u ; and add target head coma ; negative logic sta FDC_port.tr ; and store combined into track register lda drvN_tgthead,u ; copy target head into active head sta drvN_activehead,u seek_chkpos: jsr delay_5000 ; wait delay loc_E4D7: jsr fdc_getdrvstatus ; get drive status bmi locret_E53E ; drive not ready? exit bne loc_E508 ; error bit in status? lda curtrk ; get current track (set by fdc_getdrvstatus) bpl loc_E50B ; positive? we have a valid track bra loc_E4F7 ; no, this track was marked defective seek_miss: ldb drvN_tgtcylinder,u ; get target track subb curtrk ; subtract track where we are aslb ; shift left addb drvN_tgthead,u ; add target head subb curhead ; subtract surface where we are on stb drv_stepdelta ; set as new positioning delta loc_E4F7: tst drv_stepdelta ; if positive, skip bpl loc_E503 jsr fdc_movetrack_out ; move a step towards trk 0 bcs loc_E508 ; error, reposition to track 0 bra seek_chkpos ; recheck loc_E503: jsr fdc_movetrack_in ; move a step towards track 69 bcc seek_chkpos ; recheck loc_E508: jmp seek_resettrk0 ; if error, reposition to track 0 loc_E50B: cmpa drvN_tgtcylinder,u ; is it the requested cylinder? bne seek_miss ; no, seek miss, reposition lda curhead ; get curside (from fdc_getdrvstatus) bita #0x20 ; is bit 5 set? bne seek_resettrk0 ; yes, reposition to trk 0 and try again cmpa drvN_tgthead,u ; is it the head to use? bne seek_miss ; no, seek miss, reposition lda drvN_activecyl,u ; fine, we have found the position ; get active cylinder asla ; shiftleft adda drvN_activehead,u ; put in active head coma ; negative logic sta FDC_port.tr ; store in track register clra ; return no error rts ; done seek_resettrk0: jsr fdc_restore_trk0 ; reposition to track 0 bcs loc_E53C ; error? return error code 1 dec seek_retrycnt ; decrement seek retry cnt lbne seek_reposition ; tries left, redo lda #0x20 ; return error 0x20 rts loc_E53C: lda #1 ; return error 1 locret_E53E: rts ;============================================= ;read specified sector into buffer fdc_readsector: lda drvN_tgtsector,u ; get the sector# to read coma ; negative logic sta FDC_port.scr ; store in sector register clra ; disable GPIB interrupts sta gpib_int1 sta sys_state ; set state = 0 tst fdc_headisloaded ; if head is not loaded, load it bne loc_E555 jsr fdc_loadhead loc_E555: lda FDC_port.str_cr ; drain FDC status lda portctrl_state oraa #ctrl_halten ; set HALTEN=1 sta portctrl_state sta portcc andcc #~cc_firq ; enable FIRQ lda #fdcmd_readsec ; issue read single sector, check head sta FDC_port.str_cr lda dummy_buffer ; trigger wait for FDC ldx #diskbuf ; DRQ occurred, load buffer index nop loc_E571: lda FDC_port.dr ; read data coma ; negative logic sta ,x+ ; store in buffer, stop CPU to wait for DRQ bra loc_E571 ; DRQ seen, loop until FIRQ ;============================================= fdc_write_sector: lda drvN_tgtsector,u ; get target sector coma sta FDC_port.scr ; store in sector register lda #1 sta sys_state ; set state=1 tst fdc_headisloaded ; if not head loaded, load it bne loc_E58E jsr fdc_loadhead loc_E58E: lda FDC_port.str_cr ; drain FDC status register lda statuscc ; get status port bita #status_drwpt ; write protect? bne loc_E5BF ; yes, skip tst drv_softwrtprotect,u ; soft write protect? bne loc_E5BF ; yes, skip clra ; disable GPIB interrupts sta gpib_int1 andcc #~cc_firq ; enable FIRQ lda portctrl_state ; set HALTEN=1 oraa #ctrl_halten sta portcc ldb #fdcmd_writesec ; issue writesector command stb FDC_port.str_cr ; to fdc sta portctrl_state ; trigger HALT-FF ldx #diskbuf ; load start of disk buffer nop loc_E5B7: lda ,x+ ; get byte from buffer coma sta FDC_port.dr ; send to disk bra loc_E5B7 ; loop until FIRQ terminate this loc_E5BF: lda statuscc ; get status port anda #status_drrdy ; mask drive ready (as amigo_s2_attention) oraa #amigo_s2_wrtprotect ; set write protect loc_E5C6: sta fdc_status ; into FDC status rts ;============================================= ; build list of sectors in a track ; depending on track/head and interleave setup_sector_table: ldx #0x10 ; counter for 16 bytes lda #0xFF ; not-used value for table loc_E5CF: sta sector_numbers-1,x ; mark sector number buffer slots as unset leax -1,x bne loc_E5CF ; loop tst format_cylinder ; cylinder <0? exit bmi locret_E60B ldx #interleave_factors ; get table index lda format_interleave ; get interleave ldb a,x ; get increment for interleave lda format_cylinder ; get cylinder asla ; *2 adda format_head ; add head mul ; multiply with interleave increment comb ; complement result andb #0xF ; in range 0-15 ; note: this effectively permutates the starting sector ; after the index hole for each track, hopefully ; shifting the track to the previous one on a way ; that a track step and read will not require another ; complete revolution. clra ; clear A ldx #sector_numbers ; get interleave table loc_E5F3: tst b,x ; check entry in sector table bpl loc_E604 ; if positive, skip sta b,x ; store the sector number subb format_interleave ; subtract interleave andb #0xF ; restrict to range 0-15 inca ; next sector number cmpa #0x10 ; at last sector? bne loc_E5F3 ; no, loop rts ; done loc_E604: decb ; we have a clash, decrement sector position bpl loc_E5F3 ; still positive, try again finding a free slot ldb #0xF ; no, set to 15 bra loc_E5F3 ; loop locret_E60B: rts ;============================================= interleave_factors: .db 10 .db 10 .db 10 .db 8 .db 10 .db 6 .db 6 .db 4 .db 10 .db 2 .db 2 .db 0 .db 3 .db 0 .db 1 .db 0 ;============================================= ; format the current track fdc_format: lda #2 sta sys_state ; set state=2 jsr setup_sector_table ; setup sector numbers lda format_cylinder ; get cylinder to format bmi loc_E63E ; negative, skip asla ; shift left ldb format_head ; get head andb #1 ; mask bit 0 pshs b ; save adda ,s+ ; add to cylinder sta format_cylinder ; store physical cylinder lda format_head ; get head anda #0xFE ; discard head number (leave D bit) sta format_head ; save loc_E63E: ldx #0x10 ; sector counter tst fdc_headisloaded ; if head not loaded, load it bne loc_E649 jsr fdc_loadhead loc_E649: lda FDC_port.str_cr ; drain FDC status lda statuscc bita #status_drwpt ; write protect? lbne loc_E7F9 ; yes, exit set write protect tst drv_softwrtprotect,u lbne loc_E7F9 ; yes, exit set write protect clra sta gpib_int1 ; disable GPIB interrupts lda FDC_port.str_cr ; drain fdc status andcc #~cc_firq ; enable FIRQ lda portctrl_state oraa #ctrl_halten ; enable HALTEN sta portcc ldb #fdcmd_writetrk ; issue WRITE TRACK cmd stb FDC_port.str_cr sta portctrl_state ; start DRQ logic lda #32 ; 32 bytes of GAP1 ldb #~0x4E ; time to explain... ; format of track: modified IBM System 34 format ; modified: some gap lengths different, missing GAP5, sector 17 ; 32 bytes of 0x4E (GAP1) ; for each sector: ; 12 bytes of 0x00 (GAP1) ; 3 bytes of 0xF5 (ID AM Sync) ; 1 byte of 0xFE (ID AM) ; 1 byte of 0xXX (Cylinder) ; 1 byte of 0xXX (Head: 0-1, 0x20-0x21) ; 1 byte of 0xXX (Sector) ; 1 byte of 0x01 (Sector length: 0=128, 1=256,...) ; 1 byte of 0xF7 (2 byte CRC) ; 22 bytes of 0x4E (GAP2) ; 12 bytes of 0x00 (GAP2) ; 3 bytes of 0xF5 (ID AM sync) ; 1 byte of 0xFB (Data AM) ; 256 bytes of 0xXX (data, fill byte) ; 1 byte of 0xF7 (2 byte CRC) ; 46 bytes of 0x4E (GAP3) ; ; last sector as the others, but sector#=17 ; and sector length=0 (128 bytes) ; containing: ; 3 bytes of disk wear count ; 1 byte of 0xFF (initial value) ; 1 byte of 0xA4 (initial value) ; 1 byte of 0xEA (initial value) ; 122 bytea of 0xXX (filler) loc_E679: stb FDC_port.dr ; store data deca ; decrement counter sta dummy_buffer ; reenable DRQ logic bne loc_E679 ; loop ldb #~0 ; part 2 of GAP1 format_sector: lda #12 ; counter loc_E686: stb FDC_port.dr ; store data deca ; decrement counter sta dummy_buffer ; reenable DRQ logic bne loc_E686 ; loop lda #3 ldb #~0xF5 ; ID AM sync loc_E693: stb FDC_port.dr ; store data deca ; decrement counter sta dummy_buffer ; reenable DRQ logic bne loc_E693 ; loop ldb #~0xFE ; ID AM stb FDC_port.dr ; store data ldb format_cylinder ; reenable DRQ logic comb ; negative logic nop stb FDC_port.dr ; store track# ldb format_head ; reenable DRQ logic comb ; negative logic nop stb FDC_port.dr ; store head# ldb sector_number-1,x ; get sector# from table comb ; negative logic nop stb FDC_port.dr ; store data sta dummy_buffer ; reenable DRQ logic ldb #~1 ; sector length (256) nop stb FDC_port.dr ; store data sta dummy_buffer ; reenable DRQ logic ldb #~0xF7 ; 2 byte CRC nop stb FDC_port.dr ; store data sta dummy_buffer ; reenable DRQ logic lda #22 ldb #~0x4E ; ID GAP2 loc_E6D3: stb FDC_port.dr ; store data deca ; decrement count sta dummy_buffer ; reenable DRQ logic bne loc_E6D3 ; loop lda #12 ldb #~0 ; ID GAP2 loc_E6E0: stb FDC_port.dr ; store data deca ; decrement counter sta dummy_buffer ; reenable DRQ logic bne loc_E6E0 ; loop lda #3 ldb #~0xF5 ; ID AM Sync loc_E6ED: stb FDC_port.dr ; store data deca ; decrement counter sta dummy_buffer ; reenable DRQ logic bne loc_E6ED ; loop ldb #~0xFB ; DATA AM stb FDC_port.dr ; store data clra ; counter=256 ldb format_filler ; get filler byte comb ; negative logic nop loc_E701: stb FDC_port.dr ; store data deca ; decrement sta dummy_buffer ; reenable DRQ logic bne loc_E701 ; loop ldb #~0xF7 ; 2 byte CRC stb FDC_port.dr ; store data sta dummy_buffer ; reenable DRQ logic ldb #45 lda #~0x4E loc_E716: sta FDC_port.dr ; store data decb ; decrement stb dummy_buffer ; reenable DRQ logic bpl loc_E716 ; loop leax -1,x ; decrement sector count lbne format_sector ; not all sectors, loop ; note: B is now FF, as required for part2 of GAP1 ldb #~0 lda #12 ; GAP1 for sector 17, if required loc_E729: stb FDC_port.dr ; store data deca ; decrement sta dummy_buffer ; reenable DRQ logic bne loc_E729 ; loop lda #3 ldb #~0xF5 ; ID AM Sync loc_E736: stb FDC_port.dr ; store data deca ; decrement sta dummy_buffer ; reenable DRQ logic bne loc_E736 ; loop ldb #~0xFE ; ID AM stb FDC_port.dr ; store data ldb format_cylinder ; reenable DRQ logic comb ; negative logic nop stb FDC_port.dr ; store cylinder# ldb format_head ; reenable DRQ logic comb ; negative logic nop stb FDC_port.dr ; store head# sta dummy_buffer ; reenable DRQ logic ldb #17 ; load sector# 17 comb stb FDC_port.dr ; store sector# sta dummy_buffer ; reenable DRQ logic ldb #~0 ; sector length 0 (128 bytes) nop stb FDC_port.dr ; store data sta dummy_buffer ; reenable DRQ logic ldb #~0xF7 ; 2 byte CRC nop stb FDC_port.dr ; store data sta dummy_buffer ; reenable DRQ logic lda #22 ldb #~0x4E ; GAP2 loc_E776: stb FDC_port.dr ; store data deca ; decrement sta dummy_buffer ; reenable DRQ logic bne loc_E776 ; loop lda #12 ldb #~0 ; GAP2 loc_E783: stb FDC_port.dr ; store data deca sta dummy_buffer bne loc_E783 lda #3 ldb #~0xF5 ; ID AM Sync loc_E790: stb FDC_port.dr ; store data deca ; decrement sta dummy_buffer ; reenable DRQ logic bne loc_E790 ; loop ldb #~0xFB ; DATA AM stb FDC_port.dr ; store data ldb drvN_wearh,u ; reenable DRQ logic comb ; negative logic nop stb FDC_port.dr ; write 3 bytes of disk wear count ldb drvN_wearm,u comb nop stb FDC_port.dr ldb drvN_wearl,u comb nop stb FDC_port.dr ldb #~0xFF ; store 0xFF stb dummy_buffer ; reenable DRQ logic comb ; negative logic nop stb FDC_port.dr ; store data ldb #~0xA4 ; store 0xA4 stb dummy_buffer ; reenable DRQ logic comb nop stb FDC_port.dr ; store data ldb #~0xEA ; store 0xEA stb dummy_buffer ; reenable DRQ logic comb ; negative logic nop stb FDC_port.dr ; store data lda #122 ldb format_filler ; get filler comb nop loc_E7DE: stb FDC_port.dr ; store data deca ; decrement sta dummy_buffer ; reenable DRQ logic bne loc_E7DE ; loop ldb #~0xF7 ; 2 byte CRC stb FDC_port.dr ; store data sta dummy_buffer ; reenable DRQ logic ldb #~0x4E ; GAP4 loc_E7F1: stb FDC_port.dr ; store data sta dummy_buffer ; reenable DRQ logic bra loc_E7F1 ; loop until FDC interrupt (end of track) loc_E7F9: lda statuscc ; get drive ready anda #status_drrdy ; mask only bit 7 oraa #amigo_s2_wrtprotect ; set write protect sta fdc_status ; store status rts ;============================================= ; format the entire disk fdc_format_disk: jsr fdc_getdrvstatus ; check disk status lbmi locret_E91D ; drive not ready? exit bne loc_E835 ; errors, skip lda drvN_selectmask,u ; drive selected? bne loc_E844 ; yes, skip clr drvN_tgthead,u ; clear target position clr drvN_tgtcylinder,u clr drvN_tgtsector,u jsr fdc_seek ; seek to track 0, head 0, sector 0 bne loc_E835 ; error, exit lda #2 sta sys_state ; set state=2 jsr find_sector17 ; check whether sector 17 exists bne loc_E835 ; no, skip lda #1 sta has_sec17 ; flag: have wear data from sector17 bra loc_E844 ; skip loc_E835: lda #0xFE ; errors reading, set wear count very high sta drvN_wearh,u clra sta drvN_wearm,u sta drvN_wearl,u loc_E844: jsr fdc_restore_trk0 ; position to track 0 clr drvN_tgthead,u ; clear position clr drvN_tgtcylinder,u clr drvN_tgtsector,u loc_E853: jsr fdc_movetrack_in ; position to head 1 lda drvN_curtrk,u ; get current track cmpa #17 ; is it 17? (parking position) bne loc_E853 ; no, loop jsr delay_5000 ; wait some time jsr fdc_checkmotorspeed ; check motor speed bcc loc_E86C ; if okay, skip lda #amigo_s2_wrtprotect ; return WRITE PROTECT status (!) sta fdc_status rts loc_E86C: jsr fdc_restore_trk0 ; go back to track 0 loc_E86F: jsr delay_5000 ; wait some time tst override_old_fmt ; check format override bne loc_E893 ; if set, skip jsr fdc_getdrvstatus ; not override ; get drive status lbmi loc_E914 ; if drive not ready, exit bne loc_E893 ; if error, skip lda curhead ; get current head bmi loc_E889 ; negative, skip bita #0x20 ; is D bit set? beq loc_E893 ; no, skip loc_E889: lda #0xFF ; set cylinder and head to invalid sta format_cylinder sta format_head bra loc_E8A1 ; continue loc_E893: lda drvN_tgtcylinder,u ; get target sta format_cylinder ; store it lda drvN_tgthead,u sta format_head loc_E8A1: jsr fdc_format ; format that track bne loc_E914 ; if error, exit ldy #0x89 ; small delay loc_E8AA: leay -1,y bne loc_E8AA ; loop jsr fdc_movetrack_in ; next track bcs loc_E8BD ; if end of disk, skip tst format_cylinder ; cylinder is negative? bmi loc_E86F ; loop jsr fdc_nextsector1 ; advance to next secotr bra loc_E86F ; loop loc_E8BD: jsr fdc_restore_trk0 ; go back to trk 0 jsr delay_5000 ; wait some time clra sta drvN_tgtcylinder,u ; reset target sta drvN_tgthead,u sta drvN_tgtsector,u jsr fdc_seek ; position to there bne loc_E914 ; if error, exit lda drvN_selectmask,u ; get drive select bne loc_E8F0 ; set, skip tst has_sec17 ; had sector 17? bne loc_E8F0 ; yes, skip lda #0xE7 ; set a rather high value for wear level sta drvN_wearh,u clr drvN_wearm,u clr drvN_wearl,u bra loc_E906 ; skip loc_E8F0: lda #90 ; add some wear to the current value adda drvN_wearl,u sta drvN_wearl,u bcc loc_E906 inc drvN_wearm,u bne loc_E906 inc drvN_wearh,u loc_E906: clra ; disable GPIB interrupt sta gpib_int1 sta sys_state ; set state=0 jsr write_sector17 ; store the current wear count clra sta drvN_selectmask,u ; unselect disk, return error=0 loc_E914: sta dummy_buffer ; save A clr has_sec17 ; clear flag for sector17 lda dummy_buffer ; restore A locret_E91D: rts ; done ;============================================= verify_sectors: tst drvN_tgtsector,u ; is target sector=0? bne loc_E929 ; no, skip jsr fdc_seek ; reposition bne locret_E93E ; if error, exit loc_E929: jsr fdc_readsector ; read a sector bne locret_E93E ; if error, eixt jsr fdc_nextsector ; advance to next sector bcs loc_E93D ; if end of disk, exit ldx verify_seccnt ; get sector counter leax -1,x ; decrement stx verify_seccnt ; store sector counter bne verify_sectors ; not finished, loop loc_E93D: clra ; finished, no error locret_E93E: rts ;============================================= ; decode the error from drive in A ; bit 7: no disc/drive not ready ; bit 6: write protect ; bit 5: track not found ; bit 4: sector not found ; bit 3: CRC error on read or verify ; bit 2: retryable HW error ; bit 1: unused ; bit 0: drive fault set_s2_error: bita #0x40 ; test bit 6 beq loc_E952 ; not set, skip ldb #amigo_s1_status2_err ; status 2 error stb s1_errcode ldb #amigo_s2_wrtprotect ; write protect orab drvN_s2flags,u ; add to S2 bits stb drvN_s2flags,u loc_E952: bita #0x20 ; test bit 5 beq loc_E95B ; not set, skip ldb #amigo_s1_cylcmp_err ; cylinder not found stb s1_errcode loc_E95B: bita #0x10 ; test bit 4 beq loc_E964 ; not set, skip ldb #amigo_s1_seccmp_err ; sector not found stb s1_errcode loc_E964: bita #8 ; test bit 3 beq loc_E96D ; not set, skip ldb #amigo_s1_data_err ; data error stb s1_errcode loc_E96D: bita #4 ; test bit 2 beq loc_E976 ; not set, skip ldb #amigo_s1_rtry_hw_err ; retryable HW error stb s1_errcode loc_E976: bita #0x80 ; test bit 7 beq loc_E995 ; not set, skip ldb #amigo_s1_status2_err ; status 2 error stb s1_errcode ldb #0x80 ; set status 2 error flags orab drvN_disktype,u stb drvN_disktype,u ldb #amigo_s2_drivenotready ; drive not ready (no disc) orab drvN_s2flags,u andb #~amigo_s2_wrtprotect ; unset write protect stb drvN_s2flags,u loc_E995: bita #1 ; test bit 0 beq locret_E9B2 ; not set, exit ldb #amigo_s1_drvatt ; drive attention stb s1_errcode ldb drvN_disktype,u orab #0x80 ; set error bit for S2 error stb drvN_disktype,u ldb drvN_s2flags,u orab #amigo_s2_drvfault ; drive defective stb drvN_s2flags,u locret_E9B2: rts ;============================================= ; main processing loop ; unless GPIB becomes active, ; check disk quality if disk is spinning, ; update the wear counters on disk ; and otherwise just wait for a request from GPIB mainloop: ldx #0xFFF0 ; large counter ldy #0xFFF0 ; large counter tst fdc_headisloaded ; is head loaded? bne loc_E9C3 ; no, skip ldy #0x5A ; smaller delay loc_E9C3: tst gpib_apt_flag ; was last command interrupted by readdressing? bne select_secondary ; yes, skip lda #4 sta sys_state ; set state=4 loc_E9CD: tst fdc_headisloaded ; is head loaded? beq loc_E9E4 ; no, skip andcc #~cc_irq ; reenable IRQ leay -1,y ; decrement Y delay bne loc_EA07 ; not yet zero, continue with GPIB ; yes, timeout occurred, handle it jsr fdc_chk_diskquality ; check whether disks are still usable jsr fdc_unloadhead ; unload head ldy #0x5A ; small delay orcc #cc_irq ; disable IRQ loc_E9E4: lda drvN_disk_wornout ; is one of the disks worn out? oraa drvN_disk_wornout+1 beq loc_E9F1 ; no, skip jsr rfdc_reformdisk ; there is a disk of suspicious quality ; try reseating it bra mainloop ; loop loc_E9F1: tst motoron_flg ; is motor on? beq loc_EA07 ; no, skip leax -1,x ; delay loop bne loc_EA07 leay -1,y ; more delay bne loc_EA07 ; timeout jsr park_heads_at_17 ; park heads jsr fdc_motoroff ; set motor off jsr fdc_select_drv0 ; select drive 0 loc_EA07: lda gpib_ad01 ; get GPIB INT flag bpl loc_E9CD ; no int from GPIB, skip gpib_handle_int: lda gpib_int1 bita #ints1_dec ; Device clear active state? lbne do_dcas ; yes, skip loc_EA13: bita #ints1_apt ; must recognize secondary address bne select_secondary loc_EA17: bita #ints1_bi ; byte input interrupt beq loc_E9CD ; no, skip lda gpio_dio ; actually gpib_dio: read byte bra loc_E9CD select_secondary: clr gpib_apt_flag orcc #cc_irq ; disable interrupt lda gpib_am ; read address status bita #as_lpas ; has seen listener primary? beq loc_EA30 ; no, skip jsr amigo_listen ; handle amigo listen command jmp mainloop loc_EA30: bita #as_tpas ; has seen talker primary? bne loc_EA38 ; yes, skip bita #as_ta ; is talker addressed? beq loc_E9CD ; no, skip loc_EA38: bita #as_mjmn ; is a talker: major or minor mode? bne loc_EA42 ; minor mode: skip jsr amigo_talk ; handle amigo talk commands jmp mainloop loc_EA42: lda gpib_auxm ; get passthru value (secondary address) anda #0x1F ; mask only 5 bits sta fdc_status ; save secondary address ; (fdc_status used as temp) lda gpib_ad01 ; get address anda #0x1F ; mask 5 bits cmpa fdc_status ; compary with secondary presented bne loc_EAA0 ; not the same, skip jsr gpib_validsecondary ; secondary is valid ; special command prim=31, sec=addr, ID1, ID4+EOI loc_EA55: jsr gpib_assert_minortalker ; verify we are in minor mode lbcc loc_E9CD ; no, ignore lda gpib_ad01 ; loop until GPIB interrupt bpl loc_EA55 ldb gpib_int1 ; get interrupt status bitb #ints1_bo ; request to send a byte? bne loc_EA73 ; yes, continue bitb #ints1_dec ; device clear reaceived? lbne do_dcas ; yes, do device clear bitb #ints1_apt ; verify secondary? bne select_secondary ; yes, do it jmp loc_EA17 ; go drain input loc_EA73: lda #1 ; ID1 sta gpio_dio ; send ID1 byte lda #4 ; ID4 loc_EA79: jsr gpib_assert_minortalker ; verify still in minor mode lbcc loc_E9C3 ; no, ignore ldb gpib_ad01 ; get interrupt flag bpl loc_EA79 ; wait until interrupt ldb gpib_int1 ; get interrupt status bitb #ints1_bo ; request to send a byte? bne loc_EA97 ; yes, continue bitb #ints1_dec ; device clear? lbne do_dcas ; do device clear bitb #ints1_apt ; verify secondary? beq loc_EA17 ; no drain input jmp select_secondary ; handle secondary ; send byte with EOI loc_EA97: ldb #6 ; set EOI stb gpib_auxm sta gpio_dio ; send ID4 byte jmp loc_E9CD ; return to main loop loc_EAA0: jsr gpib_invalidsecondary jmp loc_E9C3 ;============================================= ; verify we are in minor mode gpib_assert_minortalker: ldb gpib_am ; get address mode bitb #as_tpas ; talker addressed? bne loc_EAB0 ; yes, continue bitb #as_ta ; talker addressed? beq loc_EAB7 ; no, exit with CY=0 loc_EAB0: bitb #as_mjmn ; major mode? beq loc_EAB7 ; yes, exit with CY=0 orcc #cc_c ; return with CY=1 rts loc_EAB7: andcc #~cc_c ; clear CY rts ;============================================= ; IRQ is generated on index pulse of FDC if enabled ; provided CLRIndex is not set (bit3 of portctrl) irq_vector: inc drvN_irqwearl,u ; increment index pulse counter (24 bit) bne loc_EACA inc drvN_irqwearm,u bne loc_EACA inc drvN_irqwearh,u loc_EACA: lda portctrl_state ; get port ctrl anda #~ctrl_clridx ; reset index flipflop (IRQ generator) sta portcc ; by setting clear input to 0 oraa #ctrl_clridx ; set clear input to 1 again sta portcc rti ; return from interrupt ;============================================= ; check whether disks are still usable fdc_chk_diskquality: orcc #cc_irq ; disable IRQ lda #0x80 sta sys_state ; set state=0x80 stu saveu ; save U lda drvN_irqwearh,u ; get high wearlevel bne loc_EAF0 ; not zero lda drvN_irqwearm,u ; get medium wear level cmpa #4 ; about 1000 bcs loc_EB0A ; less than 1000 loc_EAF0: andcc #~cc_firq ; disable FIRQ jsr fdc_parkdrive ; park drive and update wear info orcc #cc_firq ; reenable FIRQ lda drvN_wearh,u ; is drive wear > f7? cmpa #0xF7 bcc loc_EB04 ; yes, skip jsr fdc_check_worndisk ; measure speed of disk bra loc_EB0A loc_EB04: lda #1 ; shouldn't use this disk any more sta drvN_disk_wornout,u loc_EB0A: lda drive_ptr+1 ; toggle drive selecton coma anda #1 sta drive_ptr+1 ldu drive_ptr ; select the other drive lda drvN_irqwearh,u ; get high wear level bne loc_EB24 ; not zero, skip lda drvN_irqwearm,u ; get medium wear level cmpa #4 ; about 1000? bcs loc_EB43 ; less, skip loc_EB24: orcc #cc_firq ; disable FIRQ jsr fdc_waitrdy_select_curdrv ; wait for drive andcc #~cc_firq ; enable FIRQ jsr fdc_parkdrive ; park it and update wear info orcc #cc_firq ; disable FIRQ lda drvN_wearh,u ; is drive wear > F7? cmpa #0xF7 bcc loc_EB3D ; yes, skip jsr fdc_check_worndisk ; measure speed of disk bra loc_EB43 ; continue loc_EB3D: lda #1 ; mark disk as worn out sta drvN_disk_wornout,u loc_EB43: ldu saveu ; restore old selected disk stu drive_ptr orcc #cc_firq ; disable FIRQ jsr fdc_waitrdy_select_curdrv ; wait for disk ready clr sys_state ; set state=0 rts ;============================================= ; park drive at position 0 and update wear info fdc_parkdrive: orcc #cc_firq ; disable FIRQ jsr fdc_inactivate_drive ; mark drive as inactive lda drvN_storecyl,u ; cylinder or head not 0 bne loc_EB65 lda drvN_storehead,u bne loc_EB65 ; yes, move to track 0 bra at_trk0 ; is at track 0 loc_EB65: lda drvN_curtrk,u ; get current track bne loc_EB71 ; not 0 lda drvN_curhead,u beq move_to_trk0 loc_EB71: orcc #cc_firq ; disable FIRQ jsr fdc_movetrack_out ; step a track towards trk0 jsr decrement_storedpos ; adjust store pos andcc #~cc_firq ; reenable FIRQ bra loc_EB65 ; loop move_to_trk0: lda FDC_port.str_cr ; get FDC status bita #fdc_status1_trk0 ; check trk0 bit beq at_trk0 ; if at trk0, skip orcc #cc_firq ; disable FIRQ jsr fdc_movetrack_out ; move a single step andcc #~cc_firq ; reenable FIRQ bra move_to_trk0 ; loop at_trk0: andcc #~cc_firq ; re-enable FIRQ jsr delay_5000 ; wait some time jsr fdc_getdrvstatus ; read drive position lbne loc_EC1B ; error, exit lda curtrk ; is track positive? bpl loc_EBA9 ; yes, skip realign: orcc #cc_firq ; disable FIRQ jsr fdc_movetrack_in ; move track back in lbcs locret_EC2B ; if error, exit bra at_trk0 ; loop until at track 0 loc_EBA9: bne realign ; not yet at 0, realign lda curhead ; is also head=0? bne realign ; no realign sta drvN_storecyl,u ; set position to true zero sta drvN_storehead,u lda #~0 ; set track register = 0 sta FDC_port.tr tst drvN_updatewear,u ; has wear information? bne has_wearinfo ; yes, skip lda #5 ; try 5 times to get the wear info sta readwear_retrycnt loc_EBC8: jsr read_sector17 ; get sector 17 of track 0 beq has_wearinfo ; was okay, skip (now have wear info) bmi locret_EC2B ; drive not ready, exit dec readwear_retrycnt ; retry getting sector bne loc_EBC8 ; loop bra loc_EC1B ; restart with wear level 0 has_wearinfo: lda drvN_wearh,u ; get wear info from drive cmpa #0xFE ; was just initialized? bcc loc_EC2C ; higher, skip lda drvN_wearl,u ; get wear info from drive adda drvN_irqwearl,u ; add revolution count orcc #cc_firq ; disable FIRQ sta drvN_wearl,u ; store it lda drvN_wearm,u ; add middle and high bytes adca drvN_irqwearm,u sta drvN_wearm,u lda drvN_wearh,u adca drvN_irqwearh,u sta drvN_wearh,u bcc loc_EC0C ; if carry? set to 0xfe lda #0xFE sta drvN_wearh,u loc_EC0C: andcc #~cc_firq ; re-enable FIRQ lda #1 ; mark we have wear info to write sta drvN_updatewear,u jsr write_sector17 ; write it to disk clr drvN_updatewear,u ; clear flag loc_EC1B: orcc #cc_firq ; disable FIRQ clr drvN_irqwearh,u ; clear revolution count clr drvN_irqwearm,u clr drvN_irqwearl,u andcc #~cc_firq ; re-enable FIRQ locret_EC2B: rts loc_EC2C: lda #1 ; soft write protect? sta drv_softwrtprotect,u sta drvN_disk_wornout,u clr drvN_irqwearh,u ; clear index counter (24 bit) clr drvN_irqwearm,u clr drvN_irqwearl,u rts ;============================================= ; try 5 times reading sector 17 find_sector17: lda #5 ; 5 attempts sta readwear_retrycnt loc_EC48: clra ; disable GPIB interupts sta gpib_int1 jsr read_sector17 ; read disk wear parameters beq locret_EC5A ; no error, exit bmi locret_EC5A ; drive not ready, exit dec readwear_retrycnt ; retry bne loc_EC48 ; loop lda fdc_status ; get last status locret_EC5A: rts ;============================================= ; read the sector containing the disk wear count ; which is trk0, head0, sector17 ; disk wear is number of revolutions + number of steps/4 read_sector17: tst fdc_headisloaded ; is head loaded? bne loc_EC63 ; no, load it jsr fdc_loadhead loc_EC63: lda #~17 ; load sector 17 sta FDC_port.scr ; into sector register lda FDC_port.str_cr ; drain status register andcc #~cc_firq ; enable FIRQ lda portctrl_state oraa #ctrl_halten ; set HALTEN bit sta portcc ldb #fdcmd_readsec ; issue single sector read / Side compare flg 1 stb FDC_port.str_cr sta portctrl_state ; trigger DRQ/HALTEN/FIRQ logic nop ; dummy nop lda FDC_port.dr ; DRQ occured: read data coma ; negative logic sta drvN_wearh,u ; save drive wear count nop nop lda FDC_port.dr ; DRQ occurred: read data coma ; negative logic sta drvN_wearm,u ; save drive waer count nop nop lda FDC_port.dr ; DRQ occurred, read data coma sta drvN_wearl,u ; save drive wear count nop nop drain_wearread: lda FDC_port.dr ; DRQ occurred coma ; negative logic sta dummy_buffer ; drain data bra drain_wearread ; loop until final FIRQ (end of record) ;============================================= write_sector17: tst fdc_headisloaded ; if not head loaded, load it bne loc_ECAE jsr fdc_loadhead loc_ECAE: lda #~17 ; set sector 17 sta FDC_port.scr lda FDC_port.str_cr ; drain FDC status andcc #~cc_firq ; enable FIRQ lda portctrl_state oraa #ctrl_halten ; set HALTEN=1 sta portcc ldb #fdcmd_writesec1 ; issue WRITESECTOR cmd stb FDC_port.str_cr sta portctrl_state ; enable DRQ logic nop nop lda drvN_wearh,u ; store three wear bytes coma sta FDC_port.dr lda drvN_wearm,u nop nop coma sta FDC_port.dr lda drvN_wearl,u nop nop coma sta FDC_port.dr lda #0 ; store 0x00 sta dummy_buffer ; reenable DRQ logic coma ; negative logic nop sta FDC_port.dr ; store data lda #0x5B ; store 0x5B sta dummy_buffer coma nop sta FDC_port.dr lda #0x15 ; store 0x15 sta dummy_buffer coma nop sta FDC_port.dr clra ; store 0x00 loc_ED05: sta dummy_buffer ; reenable DRQ logic coma nop sta FDC_port.dr ; store data bra loc_ED05 ; loop until FDC Int ;============================================= ; try to find out if disk is still usable fdc_check_worndisk: ldy #0 ; counter lda FDC_port.tr ; get track sta FDC_port.dr ; set to target to reach lda #fdcmd_seek sta FDC_port.str_cr loc_ED1E: lda gpib_ad01 ; get GPIB interrupt bmi fdc_diskchk_gpib_int ; yes, continue jsr nullsub_1 ; wait jsr nullsub_1 lda FDC_port.str_cr ; get drive status bita #fdc_status1_busy ; is busy? beq loc_ED1E ; yes, loop loc_ED2F: leay -1,y ; decrement count bne loc_ED34 ; exit if timeout rts loc_ED34: lda gpib_ad01 ; get GPIB interrupt? bmi fdc_diskchk_gpib_int ; yes, continue lda FDC_port.str_cr ; get drive status anda #fdc_status1_index ; index seen? beq loc_ED2F ; yes ldy #0 ; reset counter loc_ED43: leay -1,y ; decrement counter bne loc_ED48 ; skip rts ; exit if timeout loc_ED48: lda gpib_ad01 ; get GPIB interrupt? bmi fdc_diskchk_gpib_int ; yes, skip lda FDC_port.str_cr ; get stauts anda #fdc_status1_index ; index pulse? bne loc_ED43 ; no, loop ldy #12000 ; load counter loc_ED57: lda gpib_ad01 ; if GPIB interrupt bmi fdc_diskchk_gpib_int ; yes, exit leay -1,y ; decrement counter bne loc_ED57 ; loop jsr fdc_measure_speed ; measure drive speed cmpx #764 ; is lower than 764 bls locret_ED6D ; exit lda #1 sta drvN_disk_wornout,u ; set flag disk no longer okay locret_ED6D: rts fdc_diskchk_gpib_int: jmp loc_EE03 ; handle gpib int ;============================================= ; reforming/reseating seems to try to move the heads between inner and outer most track ; several times, after that, the wear count is reset rfdc_reformdisk: lda #1 sta drive_cnt ; counter sta byte_1AA ; this is written but never used again stu saveu ; save current disk lda drive_ptr+1 ; select disk 0 or 1 anda #1 sta drive_ptr+1 ldu drive_ptr ; select this disk ldx #1055 ; counter loc_ED8A: cmpu #0 ; is drive 0? beq loc_ED94 ; yes switch to disk 1 leau -1,u ; decrement drive bra loc_ED96 ; continue loc_ED94: leau 1,u ; select drive 1 loc_ED96: lda drvN_disk_wornout,u ; get wornout flag beq loc_ED8A ; not set, try the other drive loc_ED9C: stu drive_ptr ; okay, this disk is suspicious jsr fdc_waitrdy_select_curdrv ; select it jsr fdc_inactivate_drive ; set inactive ldy #0 ; counter jsr fdc_unloadhead ; unload head loc_EDAC: lda gpib_ad01 ; if GPIB interrupt, discard operation bmi loc_EE03 lda statuscc ; get port status bmi loc_EDFE ; drive not ready, skip leay -1,y ; decrement counter bne loc_EDAC ; loop lda portctrl_state ; load head oraa #ctrl_hdld sta portctrl_state sta portcc lda #1 ; set head loaded sta fdc_headisloaded ldy #3072 ; some delay loc_EDCD: lda gpib_ad01 ; if GPIB interrupt, discard operation bmi loc_EE03 leay -1,y ; wait bne loc_EDCD lda drive_cnt,u ; flag is 1? bne loc_EDE5 ; yes, skip jsr fdc_movetrack_out ; step towards trk 0 bcs loc_EDEF ; error, skip jsr decrement_storedpos ; adjust stored position bra loc_EDFA ; skip loc_EDE5: jsr fdc_movetrack_in ; move towards track 69 bcs loc_EDEF ; error, exit jsr increment_storedpos ; adjust stored position bra loc_EDFA ; skip loc_EDEF: lda drive_cnt,u ; select other drive coma anda #1 sta drive_cnt,u loc_EDFA: leax -1,x ; decrement counter bne loc_ED8A ; not zero, skip loc_EDFE: jsr fdc_unloadhead ; unload head bra reform_done ; done loc_EE03: jsr fdc_unloadhead ; unload head ldu saveu ; get saved drive ptr stu drive_ptr ; set it jsr fdc_select_curdrv ; select this drive clr sys_state ; set state=0 lda gpib_int1 ; check int status bita #ints1_dec ; device clear? lbne do_dcas ; yes, clear device lds #stacktop ; reset stack jmp loc_EA13 ; handle interrupt further reform_done: clra ; clear flag sta drvN_disk_wornout,u ; clear flag sta drv_softwrtprotect,u ; clear soft write protect sta drvN_wearh,u ; clear usage counters sta drvN_wearm,u sta drvN_wearl,u sta drvN_updatewear,u ; don't need to update sta drvN_selectmask,u ; drive selection mask sta sys_state ; set state=0 cmpu #0 ; was drive 0 beq loc_EE4B ; yes, try the other one leau -1,u ; was drive one, try the other bra loc_EE4D ; continue loc_EE4B: leau 1,u ; select drive 1 loc_EE4D: lda drvN_disk_wornout,u ; is it marked as suspicious? beq loc_EE56 ; no, finished jmp loc_ED9C ; try reforming this loc_EE56: ldu saveu ; restore old selection stu drive_ptr jsr fdc_waitrdy_select_curdrv ; select the current drive rts ;============================================= ; park all heads at track 17 park_heads_at_17: stu saveu ; save current drive ptr jsr park_head_at_17 ; park drive head at track 17 lda drive_ptr+1 ; toggle to other drive coma anda #1 sta drive_ptr+1 ldu drive_ptr jsr fdc_waitrdy_select_curdrv ; select it jsr park_head_at_17 ; park head ldu saveu ; restore drive ptr stu drive_ptr jsr fdc_waitrdy_select_curdrv ; select drive rts ;============================================= ; park head of selected drive to track 17 park_head_at_17: jsr fdc_inactivate_drive ; set drive inactive loc_EE85: lda gpib_ad01 ; GPIB interrupt? bmi loc_EEA4 ; yes, skip lda drvN_curtrk,u ; get track position cmpa #17 ; is it 17? beq locret_EEA3 ; yes, exit bhi loc_EE9B ; is it higher? jsr fdc_movetrack_in ; move head towards track 17 in jsr increment_storedpos ; adjust stored position bra loc_EE85 ; loop loc_EE9B: jsr fdc_movetrack_out ; position head out jsr decrement_storedpos ; decrement position bra loc_EE85 ; loop locret_EEA3: rts loc_EEA4: lds #stacktop ; reset stack ldu saveu ; restore selected drive stu drive_ptr jsr fdc_waitrdy_select_curdrv ; wait until ready jmp gpib_handle_int ; handle interrupt ;============================================= ; decrement stored position of drive after a step out decrement_storedpos: lda drvN_storehead,u ; get stored head beq loc_EEBF ; if zero, skip clr drvN_storehead,u ; set it 0 rts loc_EEBF: inc drvN_storehead,u ; set head=1 dec drvN_storecyl,u ; decrement cylinder rts ;============================================= ; increment stored position of drive after a step in increment_storedpos: lda drvN_storehead,u ; get stored head bne loc_EED3 ; is 1 inc drvN_storehead,u ; no, make one rts loc_EED3: clr drvN_storehead,u ; set to 0 inc drvN_storecyl,u ; increment cylinder rts ;============================================= ; mark drive as no longer selected, store parameters fdc_inactivate_drive: tst drvN_inactive,u ; is drive inactive? bne locret_EF08 ; yes, exit lda #1 sta drvN_inactive,u ; set in inactive lda drvN_activecyl,u ; save active clyinder sta drvN_storecyl,u lda drvN_activehead,u ; save active head sta drvN_storehead,u lda drvN_curtrk,u ; save track as reported by drive sta drvN_savedtrk,u lda drvN_curhead,u ; save head as reported by drive sta drvN_savedhead,u locret_EF08: rts ;============================================= amigo_listen: lda #8 sta sys_state ; set state 8: secondary listen lda #1 sta gpib_auxm ; disable parallel poll mode lda gpib_auxm ; get pass thru value anda #0x7F ; discard parity bit cmpa #0x6B ; secondary=0B: Buffered read verify lbeq amigo_listen0b cmpa #0x60 ; secondary=00: Receive data lbeq amigo_listen00 cmpa #0x68 ; secondary=08: seek/req status/unbuffered read/verify/ ; unbuffered write/initialize/set addr record lbeq amigo_listen08 cmpa #0x69 ; secondary=09: Buffered write lbeq amigo_listen09 cmpa #0x6A ; secondary=0a: request status/buffered read/request logaddr lbeq amigo_listen0a cmpa #0x6C ; secondary=0c: unbuf read verify/request physaddr/format/writedisk lbeq amigo_listen0c cmpa #0x6F ; secondary=0f: download lbeq amigo_download cmpa #0x71 ; secondary=11: HPIB CRC lbeq amigo_sendcrc cmpa #0x70 ; secondary=10: amigo HP300 clear lbeq amigo_hp300_clear cmpa #0x7E ; secondary=1e: write loopback lbeq amigo_writeloopback cmpa #0x7F ; secondary=1f: init selftest lbeq amigo_initselftest cmpa #0x7D ; secondary=1d: diagnose stepper bne amigo_listen_invalid tst end_buf lbne amigo_diagnostic ; do it amigo_listen_invalid: jsr gpib_invalidsecondary ; acknowledge invalid secondary jmp gpib_errorstate ; go to error state ;============================================= amigo_talk: lda #9 sta sys_state ; set amigo talk state lda #auxm_clr_pp sta gpib_auxm ; disable parallel poll mode lda gpib_auxm ; get passthru value anda #0x7F ; discard parity cmpa #0x60 ; secondary=00: send data bne loc_EF84 ; no, skip lda #auxm_v_sa sta gpib_auxm ; acknowledge valid secondary jsr assert_dsj_not_2 ; check fully initialized jmp amigo_senddata ; send up to 256+1 bytes loc_EF84: cmpa #0x68 ; secondary=08: send address or status bne loc_EF91 ; no, skip jsr gpib_validsecondary ; acknowledge valid secondary jsr assert_dsj_not_2 ; check fully initialized jmp amigo_sendstatus ; send 4+1 status bytes loc_EF91: cmpa #0x70 ; secondary=10: send DSJ lbeq amigo_senddsj cmpa #0x71 ; secondary=11: HPIB CRC lbeq amigo_sendcrc cmpa #0x7E ; secondary=1e: Read Loopback lbeq amigo_readloopback cmpa #0x7F ; secondary=1f: Read Selftest lbeq amigo_readselftest jsr gpib_invalidsecondary ; signal invalid secondary jmp gpib_errorstate ; set error state dsj=1 ;============================================= ; listen function 08 ; 00: cold load read ; 02: Seek ; 03: request status ; 05: unbuffered read ; 07: Verify ; 0B: initialize (D=0) ; 14: req logical address ; 15: End ; 2B: initialize (D=1) amigo_listen08: jsr gpib_validsecondary ; acknowledge valid command jsr gpib_readbyte ; read opcode lbcs gpib_errorstate ; if error, exit anda #0x3F ; mask out 6 bits cmpa #0 ; subfunction 0: cold read lbeq amigo_coldload ; skip to it jsr assert_dsj_not_2 ; require for the following functions ; that DSJ was correct read after powerup cmpa #5 ; subfunction 5: unbuffered read bne loc_EFD0 ; no, skip lda #1 ; set unbuffered mode sta unbufread_flg jmp fdc_read ; common read entry loc_EFD0: cmpa #8 ; subfunction 8: unbuffered write bne loc_EFDC ; no, skip lda #1 ; set unbuffered mode sta unbufwrite_flg jmp amigo_bufwrite ; common write entry loc_EFDC: cmpa #2 ; subfunction 2: seek lbeq amigo_seek ; do it cmpa #3 ; subfunction 03: read status lbeq amigo_reqstatus ; do it cmpa #7 ; subfunction 7: Verify lbeq amigo_verify ; do it cmpa #0xB ; subfunction 0B: initialize (D=0) lbeq amigo_initialize_d0 ; do it cmpa #0x14 ; subfunction 14: request logical address lbeq amigo_reqlogical ; do it cmpa #0x15 ; subfunction 15: end lbeq amigo_end ; do it cmpa #0x2B ; subfunction 2B: initialize (D=1) lbeq amigo_initialize_d1 ; do it jmp amigo_illopcode ; return illegal opcode error ;============================================= ; perform 09 functions: ; 08: buffered write amigo_listen09: lda #auxm_v_sa ; acknowledge valid secondary sta gpib_auxm jsr gpib_readbyte ; get opcode lbcs gpib_errorstate ; if error, exit anda #0x1F ; mask 5 bits cmpa #8 ; subfunction 8: buffered write lbne amigo_illopcode ; no error ill opcode jsr assert_dsj_not_2 ; require full powerup jmp amigo_bufwrite ; common write entry ;============================================= ; perform 0a functions: ; 03: request status ; 05: buffered read ; 14: request logical amigo_listen0a: lda #auxm_v_sa ; acknowledge valid secondary sta gpib_auxm jsr gpib_readbyte ; get opcode lbcs gpib_errorstate ; if error, exit jsr assert_dsj_not_2 ; require full initialization anda #0x1F ; mask 5 bits cmpa #5 ; subfunction 5: buffered read lbeq fdc_read ; yes, do it cmpa #3 ; subfunction 3: request status lbeq amigo_reqstatus ; do it cmpa #0x14 ; subfunction 14: request logical lbne amigo_illopcode ; no, error ill opcode jmp amigo_reqlogical ; do it ;============================================= ; perform 0b functions: ; 5: unbuffered read verify amigo_listen0b: jsr gpib_validsecondary ; acknowledge valid secondary jsr gpib_readbyte ; get opcode lbcs gpib_errorstate ; if error, exit anda #0x1F ; mask 5 bits of opcode cmpa #5 ; is it subfunction 5: buffered read verify? lbne amigo_illopcode ; no, exit illegal opcode jsr assert_dsj_not_2 ; require that full power up jmp fdc_read ; perform a read, effectively same as buffered read ;============================================= ; perform 0c functions: ; 14 request physical address ; 16 read disk wear count ; 18 format ; 1a write entire disk amigo_listen0c: jsr gpib_validsecondary ; acknowledge valid secondary jsr gpib_readbyte ; get opcode lbcs gpib_errorstate ; if error, exit jsr assert_dsj_not_2 ; require device powered up anda #0x1F ; mask 5 bits of opcode cmpa #0x14 ; subfunction 14: request physical addr lbeq amigo_reqphysical ; do it cmpa #0x16 ; subfunction 16: read wear lbeq amigo_readwear ; do it cmpa #0x1A ; subfunction 1a: format special lbeq amigo_writedisk ; do it cmpa #0x18 ; subfunction 18: format disk lbeq amigo_format ; do it cmpa #5 ; subfunction 5: unbuffered read lbne amigo_illopcode ; no, error illegal opcode lda #1 sta unbufread_flg ; set multisector read mode jmp fdc_read ; common read entry ;============================================= ; check if passed unit number in A is valid ; set U index to unit chk_validunit: anda #0xF ; mask lower nibble cmpa #3 ; compare with maximum unit number bls loc_F0A2 ; is 0...3? yes continue lda #amigo_s1_unitunavail ; signal error code sta s1_errcode jmp amigo_errorexit ; end command loc_F0A2: sta drive_ptr+1 ; store unit ldu drive_ptr ; load unit as index rts ;============================================= ; bootstrap amigo_coldload: jsr gpib_readbyte ; get head/sector information lbcs gpib_errorstate ; if error, exit clr drive_ptr+1 ; select drive 0 ldu drive_ptr ; get drive ptr sta temp1 ; store HHSSSSSS info anda #0x3F ; mask out sector cmpa #15 ; if >15, exit with seek error bgt coldload_error sta drvN_tgtsector,u ; save as target sector lda temp1 ; get info lsra ; shift 6 bits lsra lsra lsra lsra lsra cmpa #1 ; if >1, exit with error bgt coldload_error sta drvN_tgthead,u ; save target head clr drvN_tgtcylinder,u ; cylinder is fixed to 0 jsr fdc_waitrdy_select_curdrv ; wait for drive jsr fdc_spinup ; start motor jsr fdc_seek ; position to track beq do_coldload ; no error, contiune jsr set_s2_error ; decode drive errors lda #1 ; set unsuccessful sta dsj jsr gpib_set_PP ; set parallel poll jsr led_on ; leave LED on rts do_coldload: lda #1 ; enable multisector read sta unbufread_flg jmp loc_F4B0 ; jump into readsector code coldload_error: lda #amigo_s1_status2_err ; status 2 error sta s1_errcode lda drvN_disktype,u ; set S2 error bit oraa #amigo_s2_attention ; set attention sta drvN_disktype,u lda drvN_s2flags,u oraa #amigo_s2_seekcheck ; invalid sector for bootstrap sta drvN_s2flags,u jmp amigo_errorexit ; goto error state ;============================================= ; HPIB CRC, return CRC byte amigo_sendcrc: jsr gpib_validsecondary ; acknowledge valid secondary jsr gpib_set_PP ; enable parallel poll lda #1 ; send a byte 1 with EOI jsr gpib_sendbyte_with_eoi bcc locret_F12A ; no error, exit drain_crc: jsr gpib_readbyte ; read a byte bcs locret_F12A ; error, exit bvc drain_crc ; no EOI, loop locret_F12A: rts ;============================================= ; read loopback record amigo_readloopback: jsr gpib_validsecondary ; aknowledge valid address ldx #0 ; load buffer start loc_F131: lda ,x+ ; get byte from buffer jsr gpib_sendbyte ; send it on bus bcs loc_F142 ; abort seen?, yes, exit cmpx #0xFF ; is it end of buffer? bne loc_F131 ; no, continue sending lda ,x ; send last byte with EOI jsr gpib_sendbyte_with_eoi loc_F142: clr s1_errcode ; S1 = success jsr gpib_set_PP ; enable parallel poll rts ; done ;============================================= ; write loopback ; read up to 256 bytes into buffer amigo_writeloopback: jsr gpib_validsecondary ; acknowledge valid secondary ldx #0 ; load start of buffer loc_F14F: jsr gpib_readbyte ; accept a byte from GPIB lbcs gpib_errorstate ; error? exit bvs loc_F161 ; EOI? yes skip sta ,x+ ; store byte and advance to next buffer pos cmpx #end_buf ; end of buffer reached? bne loc_F14F ; no loop bra loc_F163 ; yes, exit done loc_F161: sta ,x ; store last byte loc_F163: jsr gpib_set_PP ; set parallel poll rts ;============================================= ; download up to 256 bytes of 6809 code into download ; buffer and jump to beginning of code. ; ; Note: unless the code does bad things, a RTS will return to the main loop. amigo_download: jsr gpib_validsecondary ; acknowledge valid secondary ldx #downloadbuf ; load start of download buffer loc_F16D: jsr gpib_readbyte ; get a byte lbcs gpib_errorstate ; if error, exit bvs loc_F17F ; if EOF, skip sta ,x+ ; store byte, advance ptr cmpx #downloadbuf+256 ; a maximum of 256 bytes loaded? bne loc_F16D ; no, loop bra loc_F181 ; yes, call the code loc_F17F: sta ,x ; store last EOI byte loc_F181: jmp downloadbuf ; call the downloaded code ;============================================= ; read wear count of drive ; subfunction 0: current drive ; subfunction 1: drive specified by UNIT amigo_readwear: jsr gpib_readbyte ; read sub opcode lbcs gpib_errorstate ; if error, exit beq loc_F1C2 ; is it zero?, yes, skip jsr gpib_readbyte ; get unit byte lbcs gpib_errorstate ; error, exit jsr chk_validunit ; select unit sta selected_unit ; set as selected unit clr drvN_tgtcylinder,u clr drvN_tgthead,u clr drvN_endofdisk,u jsr fdc_waitrdy_select_curdrv ; select current drive jsr fdc_spinup ; start motor jsr fdc_seek ; do a seek to track 0 head 0 bne readwearfailed ; didn't succeed clra sta gpib_int1 ; disable GPIB interrupt sta sys_state ; system state is 0 jsr read_sector17 ; read the sector containing disk wear bne loc_F1EB ; reenable GPIB and error lda #inte1_bi|inte1_bo|inte1_dec|inte1_apt sta gpib_int1 ; reset GPIB interrupts bra loc_F1C9 ; continue loc_F1C2: jsr gpib_readbyte ; drain EOI lbcs gpib_errorstate ; if error, exit loc_F1C9: lda drvN_wearh,u sta status_s1 ; store 1st byte lda drvN_wearm,u sta status_s1_unit ; store 2nd byte lda drvN_wearl,u sta status_s2_type ; store 3rd byte clr dsj ; clear error code clr s1_errcode jsr gpib_set_PP ; enable parallel poll jsr led_off ; switch of LED rts loc_F1EB: ldb #inte1_bi|inte1_bo|inte1_dec|inte1_apt stb gpib_int1 ; reenable GPIB interrupts readwearfailed: jsr set_s2_error ; decode drive error lda #1 ; command unsuccessful sta dsj jsr gpib_set_PP ; enable parallel poll jsr led_on ; leave LED on rts ;============================================= ; seek position on floppy amigo_seek: jsr gpib_readbyte ; get unit number lbcs gpib_errorstate ; if error, exit jsr chk_validunit ; check valid unit and select it sta selected_unit ; save as currently selected unit jsr gpib_readbyte ; read high byte of cylinder lbcs gpib_errorstate ; if error, exit bne seek_error ; not zero, exit setting error jsr gpib_readbyte ; get low byte of cylinder lbcs gpib_errorstate ; if error, exit cmpa #34 ; is it higher than 34? bhi seek_error ; yes, error sta drvN_tgtcylinder,u ; store the target cylinder jsr gpib_readbyte ; get head lbcs gpib_errorstate ; if error, exit cmpa #1 ; is it > 1? bhi seek_error ; yes, error sta drvN_tgthead,u ; store the target head jsr gpib_readbyte ; get target sector lbcs gpib_errorstate ; if error, exit cmpa #16 ; is it >16? bhi seek_error ; yes error sta drvN_tgtsector,u ; store target sector jsr fdc_waitrdy_select_curdrv ; select drive jsr fdc_spinup ; start motor jsr fdc_seek ; seek the specified position beq seek_noerror ; no error, done jsr set_s2_error ; decode the error from drive lda #1 ; unsuccessful sta dsj jsr gpib_set_PP ; enable parallel poll jsr led_on ; leave LED on rts ; exit seek_noerror: clr dsj ; operation completed successfully jsr led_off ; switch of select LED lda #amigo_s1_drvatt ; drive atention sta s1_errcode lda drvN_disktype,u ; set disk type anda #0x7F ; without error bit sta drvN_disktype,u lda drvN_s2flags,u ; set drive attention in s2 oraa #amigo_s2_attention sta drvN_s2flags,u jsr gpib_set_PP ; set parallel poll rts ; done seek_error: lda #amigo_s1_drvatt ; signal drive attention sta s1_errcode lda drvN_disktype,u ; get disktype oraa #amigo_s2_attention ; set attention bit sta drvN_disktype,u lda drvN_s2flags,u oraa #amigo_s2_attention oraa #amigo_s2_seekcheck ; set attention and drive fault bits sta drvN_s2flags,u jmp amigo_errorexit ; exit with error ;============================================= ; command: request status ; needs amigo_talk_08 to send these bytes to controller amigo_reqstatus: jsr gpib_readbyte ; read unit byte lbcs gpib_errorstate ; if error, exit jsr chk_validunit ; check valid unit and set U cmpa selected_unit ; same as selected unit? bne loc_F2B2 ; no, do not check for last operation lda dsj ; was last operation in error? cmpa #1 beq amigo_savestatus ; yes, fill s1/s2 status bytes ; prepare status for other drive than selected one loc_F2B2: clr drvN_disktype,u ; clear disktype clr drvN_s2flags,u ; clear s2 flags jsr fdc_waitrdy_select_curdrv ; select drive jsr fdc_spinup ; start motor lda statuscc ; get write protect flag bita #status_drwpt beq loc_F2D1 ; no set, skip lda #amigo_s2_wrtprotect ; set write protect flag oraa drvN_s2flags,u sta drvN_s2flags,u ; into s2flags loc_F2D1: jsr fdc_getdrvstatus ; get drive status beq loc_F2FE ; everything okay, skip bita #0x80 ; check drive ready status beq loc_F2F2 ; is ready, but there were error bits lda #amigo_s2_attention ; set attention bit in S2 oraa drvN_disktype,u ; inject into status sta drvN_disktype,u lda #amigo_s2_drivenotready ; set drive not ready bits in S2 oraa drvN_s2flags,u anda #~amigo_s2_wrtprotect ; remove wrt protect bit - irrelevant sta drvN_s2flags,u bra amigo_savestatus loc_F2F2: lda #0xA ; disktype TTTT=0101: unformatted disk oraa drvN_disktype,u sta drvN_disktype,u bra amigo_savestatus loc_F2FE: lda #0xC ; disktype TTTT=0110: HP Format oraa drvN_disktype,u sta drvN_disktype,u ; inject TTTT bits ;============================================= ; save status of last operation amigo_savestatus: lda s1_errcode ; get current error status sta status_s1 ; save it in status byte lda selected_unit ; get selected unit sta status_s1_unit ; save it in unit byte lda drvN_disktype,u ; get disk type of last operation oraa #1 ; add flag for 9121 (in contrast to 8290X) sta status_s2_type ; save as status 2 lda drvN_s2flags,u ; get s2 flags for last operation sta status_s2_flags ; save them clr drvN_disktype,u ; clear disktype clr drvN_s2flags,u ; clear s2 status clr s1_errcode ; clear error code clr dsj ; clear DSJ jsr gpib_set_PP ; enable parallel poll jsr led_off ; turn off LED rts ;============================================= ; set D bit for sectors to write amigo_initialize_d0: jsr gpib_readbyte ; get unit lbcs gpib_errorstate ; if error, exit jsr chk_validunit ; check valid unit sta selected_unit ; and select it lda drvN_activehead,u ; get the active head anda #1 sta format_head initialize: lda drvN_activecyl,u ; get cylinder sta format_cylinder ; store it lda #2 sta format_interleave ; set interleave to 2 lda #1 sta format_track ; enable format before write jsr gpib_set_PP ; set parallel poll rts ;============================================= amigo_initialize_d1: jsr gpib_readbyte ; get unit lbcs gpib_errorstate ; if error, exit jsr chk_validunit ; check unit sta selected_unit ; select unit lda drvN_activehead,u ; get head oraa #0x20 ; set D bit in head info sta format_head ; store in header info for head bra initialize ; common init ;============================================= amigo_verify: jsr gpib_readbyte ; get unit lbcs gpib_errorstate ; if error, exit jsr chk_validunit ; check unit sta selected_unit ; select it jsr gpib_readbyte ; get sector count high lbcs gpib_errorstate ; if error, exit sta verify_seccnt ; store sector high jsr gpib_readbyte ; get sector low lbcs gpib_errorstate ; if error, exit sta verify_seccnt+1 ; store sector low ldd verify_seccnt ; get sector count in D beq loc_F3D2 ; if zero, exit lsra ; divide by 4 rorb lsra rorb addb drvN_irqwearl,u ; add to current disk wear stb drvN_irqwearl,u adca drvN_irqwearm,u sta drvN_irqwearm,u bcc loc_F3BC inc drvN_irqwearh,u loc_F3BC: jsr fdc_waitrdy_select_curdrv ; select drive jsr fdc_spinup ; start motor tst drvN_inactive,u ; is inactive beq loc_F3CD ; no, skip jsr fdc_seek ; reposition drive bne loc_F3DF ; if error, exit loc_F3CD: jsr verify_sectors ; verify sectors in loop bne loc_F3DF ; if error, exit loc_F3D2: clr s1_errcode ; clear error code clr dsj ; return success jsr gpib_set_PP ; enable parallel poll jsr led_off ; deselect LED rts loc_F3DF: jsr set_s2_error ; decode drive errors lda #1 ; unsuccessful sta dsj jsr gpib_set_PP ; set parallel poll jsr led_on ; leave LED on rts ;============================================= ; return cylinder (2bytes), head, sector of last ; (failing) operation. Use amigo talk 08 to retrieve result. amigo_reqlogical: jsr gpib_readbyte ; read and discard EOI byte lbcs gpib_errorstate ; if error, exit clr status_s1 ; clear 1st byte (cylinder high) lda drvN_tgtcylinder,u ; get cylinder sta status_s1_unit ; store as 2nd byte (cylinder low) lda drvN_tgthead,u ; get head sta status_s2_type ; store as 3rd byte lda drvN_tgtsector,u ; get sector sta status_s2_flags ; store as 4th byte clr s1_errcode ; clear error code clr dsj ; clear DSJ jsr gpib_set_PP ; enable parallel poll jsr led_off ; deselect LED rts ; done ;============================================= ; get cylinder (2 bytes) and head ; current drive is positioned ; need amigo talk 08 to retrieve result amigo_reqphysical: jsr gpib_readbyte ; drain EOI byte lbcs gpib_errorstate ; if error, exit clr status_s1 ; clear 1st byte tst drvN_inactive,u ; active? bne loc_F43A ; no, skip lda drvN_curtrk,u ; get current positioned track sta status_s1_unit ; store as 2nd byte lda drvN_curhead,u ; get current positioned head sta status_s2_type ; store as 3rd byte bra loc_F448 ; continue loc_F43A: lda drvN_savedtrk,u ; get saved trk sta status_s1_unit ; save as 2nd byte lda drvN_savedhead,u ; get saved head sta status_s2_type ; save as 3rd byte loc_F448: clr status_s2_flags ; clear 4th byte clr s1_errcode ; clear error code clr dsj ; clear DSJ jsr gpib_set_PP ; set parallel poll jsr led_off ; deselect LED rts ;============================================= ; clear error code and dsj bytes amigo_end: jsr gpib_readbyte ; drain EOI byte lbcs gpib_errorstate ; if error, exit clr dsj ; clear dsj clr s1_errcode ; clear error code jsr gpib_clr_PP ; disable parallel poll jsr led_off ; deselect LED rts ;============================================= ; read single or multiple sectors fdc_read: jsr gpib_readbyte ; get unit lbcs gpib_errorstate ; if error, exit jsr chk_validunit ; check if valid unit sta selected_unit ; and set selected lda s1_errcode ; get last error code beq loc_F490 ; was none, continue cmpa #1 ; error was illegal opcode: nonfatal, continue beq loc_F490 cmpa #0xA ; error was I/O program error: nonfatal, continue beq loc_F490 cmpa #0x1F ; was drive attention bne read_failed ; no, this is fatal tst drvN_disktype,u ; was a S2 attention? bmi read_failed ; yes, fatal loc_F490: jsr fdc_waitrdy_select_curdrv ; select drive jsr fdc_spinup ; start motor tst drvN_inactive,u ; is it inactive bne loc_F4B0 ; yes, skip lda drvN_activecyl,u ; is at the correct cylinder cmpa drvN_tgtcylinder,u bne loc_F4B0 ; no, reposition lda drvN_activehead,u ; is it at correct head cmpa drvN_tgthead,u beq loc_F4B5 ; yes, skip to reader loc_F4B0: jsr fdc_seek ; position at correct track/head bne read_error loc_F4B5: jsr fdc_readsector ; read selected sector bne read_error ; status not 0, process error clr dsj ; was successful clr s1_errcode ; no error jsr fdc_nextsector ; advance to next sector lda #9 sta gpib_auxm ; enable parallel poll jsr led_off ; deselct LED rts ; done read_error: jsr set_s2_error ; decode drive errors read_failed: lda #1 ; set unsuccessful sta dsj jsr gpib_set_PP ; enable parallel poll jsr led_on ; leave LED on clr unbufread_flg ; clear multiread flag rts ;============================================= ; select drive for writing ; actual write is performed in amigo_receivedata amigo_bufwrite: jsr gpib_readbyte ; get unit lbcs gpib_errorstate ; if error, exit jsr chk_validunit ; check if valid sta selected_unit ; select it lda #9 ; enable parallel poll sta gpib_auxm rts ;============================================= amigo_listen00: lda #auxm_v_sa ; acknowledge valid secondary sta gpib_auxm jsr assert_dsj_not_2 ; require full init tst format_track ; should format (set/reset D bits) lbne format_disk ; yes, skip lda s1_errcode ; get error code beq loc_F518 ; last cmd was okay, skip cmpa #amigo_s1_illop ; last error was ill op beq loc_F518 ; ignore cmpa #amigo_s1_ioprog_err ; last error was i/o program beq loc_F518 ; ignore cmpa #amigo_s1_drvatt ; last code was drive attention lbne loc_F5DC ; no, fatal tst drvN_disktype,u ; get disktype lbmi loc_F5DC ; has S2 attention flag set ; fatal error loc_F518: ldx #0 ; load buffer counter lda portctrl_state anda #~ctrl_clridx ; hold index interrupt sta portctrl_state orcc #cc_irq ; disable IRQ sta portcc lda #inte1_bi|inte1_bo|inte1_dec|inte1_end|inte1_apt sta gpib_int1 ; enable GPIB interrupts lda gpib_ad01 ; get GPIB interrupt status bpl loc_F540 ; no interrupt, go wait lda gpib_int1 ; get int flags bita #ints1_bi ; byte received? beq loc_F551 ; no, skip bita #ints1_end ; EOI received? beq loc_F570 ; no, skip lda gpio_dio ; get data byte sta ,x ; stor in buffer bra loc_F57F ; buffer complete loc_F540: sync ; wait for a GPIB interrupt lda gpib_int1 ; get int status cmpa #ints1_bi ; byte in interrupt? beq loc_F570 ; yes, skip cmpa #ints1_bi|ints1_end ; with EOI? bne loc_F551 ; no, skip ldb gpio_dio ; get data byte stb ,x+ ; store in buffer bra loc_F57F ; buffer complete loc_F551: bita #ints1_end ; EOI seen? bne loc_F57F ; yes, buffer complete bita #ints1_apt ; other secondary lbne loc_F5F3 ; yes, verify secondary and exit bita #ints1_dec ; device clear? beq loc_F562 ; no, skip jmp do_dcas ; do device clear loc_F562: ldb gpib_am ; get address mode bitb #as_la ; addressed as listener? bne loc_F540 ; yes, loop tst unbufwrite_flg ; is multisector? bne write_exit ; yes, skip jmp gpib_errorstate ; no, goto error loc_F570: ldb gpio_dio ; get byte from bus stb ,x+ ; store in buffer cmpx #end_buf ; buffer full? bne loc_F540 ; no, loop lda gpib_am ; get address status bita #as_eoi ; EOI seen? beq loc_F582 ; no, skip loc_F57F: clr unbufwrite_flg ; clear unbuffered mode, if set loc_F582: lda portctrl_state oraa #ctrl_clridx ; hold index interrupt sta portctrl_state sta portcc lda #inte1_bi|inte1_bo|inte1_dec|inte1_apt sta gpib_int1 ; set interrupts jsr fdc_waitrdy_select_curdrv ; select drive jsr fdc_spinup ; start motor tst drvN_inactive,u ; is drive active? bne loc_F5B1 ; no, skip lda drvN_activecyl,u ; at the right cylinder and head? cmpa drvN_tgtcylinder,u bne loc_F5B1 ; no, reposition lda drvN_activehead,u cmpa drvN_tgthead,u beq loc_F5B6 ; yes, go ahead loc_F5B1: jsr fdc_seek ; seek to right position bne loc_F5D9 ; error exit loc_F5B6: jsr fdc_write_sector ; do write the sector bne loc_F5D9 ; error, exit jsr fdc_nextsector ; advance to next sector clr dsj ; successful clr s1_errcode ; clear error code tst unbufwrite_flg ; multisector write? beq write_exit ; no, done andcc #~cc_irq ; enable IRQ again jmp loc_F518 ; go accept another sector write_exit: lda #9 ; send parallel poll sta gpib_auxm jsr led_off ; deselect LED clr unbufwrite_flg ; terminate multisector mode rts ; exit loc_F5D9: jsr set_s2_error loc_F5DC: lda #1 ; set unsuccessful sta dsj jsr gpib_set_PP ; set parallel poll jsr led_on ; leave LED on tst unbufwrite_flg ; was multiple write? beq locret_F5F2 ; no, exit clr unbufwrite_flg ; stop multiple write jmp drain_read ; drain incoming stream locret_F5F2: rts loc_F5F3: ldb #1 ; notify verify secondary flag stb gpib_apt_flag jmp gpib_errorstate ; goto error state ;============================================= format_disk: clr format_track ; clear flag again loc_F5FE: jsr gpib_readbyte ; read the filler byte bvs loc_F609 ; EOI? skip lbcs gpib_errorstate ; error, exit bra loc_F5FE ; drain until EOI loc_F609: sta format_filler ; save last byte as sector filler jsr fdc_waitrdy_select_curdrv ; select dive jsr fdc_spinup ; start motor tst drvN_inactive,u ; is inactive? beq loc_F61D ; no, skip jsr fdc_seek ; reposition drive bne init_error loc_F61D: lda format_head ; get head anda #1 ; mask head bit adda format_cylinder ; add cylinder (shifted left) adda format_cylinder sta format_tgtcylinder ; save bne loc_F63E ; not on track 0, skip clr sys_state ; clear system state jsr find_sector17 ; find sector17 on track0 bne loc_F63E ; not found or error lda #1 sta has_sec17 ; has sector17 sta drvN_selectmask,u ; set selectmask loc_F63E: jsr fdc_format ; format a track (including sector17) bne init_error ; error, exit lda format_tgtcylinder ; get formatted cylinder bne loc_F667 ; not cylinder 0, exit tst has_sec17 ; had a sector17? bne loc_F65B ; yes, skip lda #0xF7 sta drvN_wearh,u ; set a high value 0xf70000 for wear count clr drvN_wearm,u clr drvN_wearl,u loc_F65B: clra ; disable GPIB interrupts sta gpib_int1 sta sys_state ; set state=0 jsr write_sector17 ; write current disk wear count clr has_sec17 ; clear the flag loc_F667: clr dsj ; successful jsr led_off ; deselect LED clr s1_errcode ; clear error code jsr gpib_set_PP ; set parallel poll rts ; done init_error: jsr set_s2_error ; decode drive error lda #1 ; unsuccessful sta dsj clr has_sec17 clr drvN_selectmask,u ; deselect jsr gpib_set_PP ; set parallel poll jsr led_on ; leave LED on rts ;============================================= ; prepare to wait for a DCAS message amigo_hp300_clear: jsr gpib_validsecondary ; acknowledge valid command received jsr gpib_readbyte ; drain EOI byte lbcs gpib_errorstate ; error? lbvc gpib_errorstate ; not EOI? error loc_F698: lda gpib_ad01 ; get interrupt flag bpl loc_F698 ; wait until interrupt lda gpib_int1 ; get interrupt flags bita #ints1_dec ; is DCAS? beq loc_F698 ; no, wait jmp do_dcas ; do device clear ;============================================= ; initiate AMIGO selftest amigo_initselftest: jsr gpib_validsecondary ; acknowledge valid secondary jsr gpib_readbyte ; read dummy byte bcs selftest_fatal ; if CY, fatal error jsr gpib_readbyte ; read format flag bcs selftest_fatal ; if CY set, error sta stacktop ; save selftest format flag jsr selftest_chk_ram ; test RAM bcc loc_F6C1 ; no, error, continue lda #1 ; set RAM test error bra selftest_seterror ; exit selftest with error selftest_fatal: jmp gpib_errorstate ; skip loc_F6C1: jsr selftest_chk_rom ; test ROM bcc loc_F6CA ; no error, continue lda #2 ; set ROM test error bra selftest_seterror ; exit selftest with error loc_F6CA: jsr selftest_chk_fdc ; test FDC chip bcc loc_F6D3 ; no error, continue lda #4 ; set FDC chip error bra selftest_seterror ; exit with selftest error loc_F6D3: jsr selftest_chk_seek ; do seek test bcc loc_F6DC ; no error, continue lda #6 ; set SEEK test failure bra selftest_seterror ; exit with selftest error loc_F6DC: jsr selftest_chk_motor ; do motor test bcc loc_F6E5 ; no error, continue lda #5 ; set MOTOR error bra selftest_seterror ; exit with selftest error loc_F6E5: lda stacktop ; get selftest format flag anda #8 ; check "W" bit beq loc_F6F5 ; not set, skip format test jsr selftest_chk_format ; do format test bcc loc_F6F5 ; no error, continue lda #7 ; set format test error bra selftest_seterror ; exit with selftest error loc_F6F5: jsr selftest_chk_verify ; do verify test bcc selftest_noerror ; no error, continue lda #8 ; verify test error selftest_seterror: orcc #cc_c ; set carry (shift in as bit 0) rola ; make error code sta selftest_1 ; store into ST2 lda drive_ptr+1 ; get drive number asla ; put into position xxUUxxxx asla asla asla oraa #0x88 ; set E bit and 1000 -> E0UU1000 sta selftest_2 ; store into ST1 lds #stacktop ; reset stack jmp initialize_all ; initialize main loop selftest_noerror: clr selftest_2 ; clear selftest status1 clr selftest_1 ; clear selftest status2 lds #stacktop ; reset stack jmp initialize_all ; initialize mainloop ; device clear do_dcas: jsr gpib_clr_PP ; clear parallel poll mode lds #stacktop ; reinitialize stack clr dsj jsr fdc_motoroff ; deselect drive jmp device_clear ; continue device initialization ;============================================= ; DSJ command ; return DSJ byte amigo_senddsj: lda #auxm_v_sa ; acknowledge valid secondary sta gpib_auxm lda dsj ; get DSJ byte jsr gpib_sendbyte_with_eoi ; send byte lda dsj ; get status cmpa #2 ; is powerup or selftest? bne locret_F749 ; no, exit clr dsj ; operation completed jsr led_off ; set off LED locret_F749: rts ; done ;============================================= ; read selftest result: ; ST1: EHUU1000 (E=error bit, H=head#, UU=Unit) ; ST2: 000TTTTA (A=attention, test failed, ; TTTT=0001 RAM test failed ; 0010 ROM test failed ; 0100 FDC chip failed ; 0101 Motor speed error ; 0111 Format Test error ; 1000 Verify error ; 0110 Seek test failure amigo_readselftest: jsr gpib_validsecondary ; acknowledge valid secondary lda selftest_2 ; selftest result1 jsr gpib_sendbyte ; send it bcs locret_F761 ; did an error occur? ; e.g. defective hardware-> cannot send ; discard output lda selftest_1 ; selftest error code jsr gpib_sendbyte_with_eoi ; send second byte clr s1_errcode ; S1 = 0 jsr gpib_set_PP ; enable PP locret_F761: rts ; done ;============================================= amigo_format: jsr gpib_readbyte ; get unit lbcs gpib_errorstate ; if error, exit jsr chk_validunit ; check valid unit sta selected_unit ; and select it clr override_old_fmt ; clear override old format bit jsr gpib_readbyte ; get type byte lbcs gpib_errorstate ; if error, exit bpl loc_F77E ; if format bit clear, skip inc override_old_fmt ; set override=1 loc_F77E: jsr gpib_readbyte ; get interleave lbcs gpib_errorstate ; if error, exit sta format_interleave ; store interleave jsr gpib_readbyte ; get byte lbcs gpib_errorstate ; if error, exit sta format_filler ; store filler byte jsr fdc_waitrdy_select_curdrv ; select drive jsr fdc_spinup ; start motor jsr fdc_format_disk ; format entire disk bne loc_F7AA ; error, exit clr dsj ; successful jsr led_off ; deselect LED clr s1_errcode ; clear error code jsr gpib_set_PP ; set parallel poll rts ; done loc_F7AA: jsr set_s2_error ; decode disk error lda #1 ; unsuccessful sta dsj jsr gpib_set_PP ; set parallel poll jsr led_on ; leave LED on rts ; exit ;============================================= amigo_senddata: tst dsj ; check DSJ lbne senddata_eoibyte ; last command not successful, skip lda gpib_int2 ; get interrupt status2 loc_F7C2: ldx #0 ; load start of buffer lda portctrl_state anda #~ctrl_clridx ; clear index bit sta portctrl_state orcc #cc_irq ; disable IRQ sta portcc ; clear status port lda #inte2_adsc ; enable interrupt if write abort sta gpib_int2 ldb ,x+ ; get byte to send lda gpib_ad01 ; get interrupt status bpl wait_gpib_int ; no interrupt, must wait for one lda gpib_int2 ; get int status2 bita #inte2_adsc ; abort? beq loc_F7F5 ; no, wait for another interrupt lda gpib_int1 ; there was an ADSC interrupt ; get int status1 beq do_adsc ; no other interrupt? handle adsc bita #ints1_bo ; byte out requested? beq loc_F7EC ; no, skip stb gpio_dio ; send the byte loc_F7EC: bita #ints1_dec ; device clear? bne sendabort_dcas ; yes, abort bra loc_F836 ; no, continue send_loop: ldb ,x+ wait_gpib_int: sync ; wait for an interrupt from GPIB loc_F7F5: lda gpib_int1 ; get int status1 bita #ints1_bo ; byte out request? bne loc_F854 ; yes, skip bita #ints1_apt ; verify secondary? lbne loc_F8A8 ; yes, abort and leave bita #ints1_dec ; device clear? beq loc_F816 ; no, continue sendabort_dcas: clra sta gpib_int2 ; disable additiona lGPIB ints lda portctrl_state oraa #ctrl_clridx ; hold index counter sta portctrl_state sta portcc jmp do_dcas ; do device clear loc_F816: lda gpib_int2 ; get int status2 bita #ints2_adsc ; adsc interrupt? bne do_adsc1 ; yes, handle it do_adsc: lda gpib_am ; get address status bita #as_ta ; is a talker? bne loc_F826 ; yes, skip bita #as_tpas ; is primary talker? beq do_adsc1 loc_F826: bita #as_mjmn ; is major mode? beq wait_gpib_int ; yes, something else caused spurious int do_adsc1: lda gpib_ad01 ; check interrupt bpl loc_F83F ; no, abort and leave lda gpib_int1 ; get int status1 bita #ints1_bo ; byte out requested? beq loc_F836 ; no, other int stb gpio_dio ; send the byte loc_F836: bita #ints1_apt ; verify secondary? beq loc_F83F ; no, skip lda #1 ; notify verify secondary sta gpib_apt_flag loc_F83F: jsr gpib_set_PP ; set parallel poll clra sta gpib_int2 ; disable ADSC interrupt sta unbufread_flg lda portctrl_state oraa #ctrl_clridx ; set clridx bit again sta portctrl_state sta portcc rts ; exit loc_F854: stb gpio_dio ; send data byte cmpx #0x100 ; end of buffer? (256 bytes) bne send_loop ; no, loop ; finished sending the buffer lda portctrl_state oraa #ctrl_clridx ; set clrindex bit sta portctrl_state sta portcc ; in ctrl port clra sta gpib_int2 ; disable ADSC interrupt tst unbufread_flg ; multisector read requested? bne fdc_read_next_sector ; yes, skip senddata_eoibyte: lda #1 ; send a byte 1 with EOI jsr gpib_sendbyte_with_eoi loc_F873: lda #9 ; set parallel poll sta gpib_auxm clra ; clear secondary interrupt word sta gpib_int2 sta unbufread_flg ; clear multisector read rts ;============================================= fdc_read_next_sector: jsr fdc_waitrdy_select_curdrv ; select drive jsr fdc_spinup ; start motor tst drvN_inactive,u ; is inactive? bne loc_F896 ; yes, skip tst drvN_tgtsector,u ; target sector not 0? bne loc_F89B ; yes, contiune tst drvN_endofdisk,u ; end of disk reached? bne senddata_eoibyte ; yes, send EOI and terminate read loc_F896: jsr fdc_seek ; reposition to next sector bne loc_F8B0 loc_F89B: jsr fdc_readsector ; read sector from floppy bne loc_F8B0 ; disk error? skip andcc #~cc_irq ; enable index IRQ jsr fdc_nextsector ; advance to next sector jmp loc_F7C2 ; continue sending data loc_F8A8: lda #1 ; notify verify secondary sta gpib_apt_flag jmp loc_F873 ; abort and leave loc_F8B0: jsr set_s2_error ; decode S2 errors ldx #diskbuf ; gt disk buffer start loc_F8B6: lda ,x+ ; load byte and avance jsr gpib_sendbyte ; send it bcs loc_F8C7 ; if erorr, exit cmpx #0xFF ; last but one byte? bne loc_F8B6 ; no, loop lda ,x ; get last byte jsr gpib_sendbyte_with_eoi ; send byte with EOI loc_F8C7: lda #1 ; set unsuccessful sta dsj jsr led_on ; leave LED on bra loc_F873 ; exit ;============================================= amigo_sendstatus: ldx #status_s1 ; get address of status1 loc_F8D4: lda ,x+ ; load byte jsr gpib_sendbyte ; send it bcs loc_F8E5 ; if error, exit cmpx #sys_state ; 4 bytes sent? bne loc_F8D4 ; no, loop lda #1 ; send fifth dummy byte EOI jsr gpib_sendbyte_with_eoi loc_F8E5: jsr gpib_set_PP ; set parallel poll rts ;============================================= gpib_errorstate: lda #1 sta dsj ; notify DSJ error state jsr led_on ; switch on LED lda s1_errcode ; get status bne loc_F8FB ; if set, don't overwrite lda #amigo_s1_ioprog_err ; set S1= 0a (I/O program error) sta s1_errcode loc_F8FB: jsr gpib_set_PP ; set parallel poll tst gpib_apt_flag ; secondary pending? bne loc_F91E ; yes, skip lda gpib_am ; get address mode bita #as_lpas ; listener secondary requested? bne drain_read ; yes, continue bita #as_la ; listener addressed? bne drain_read ; yes, continue bita #as_tpas ; talker secondary requested? bne loc_F915 ; yes, continue bita #as_ta ; talker addressed? beq loc_F91E ; no, ignore that loc_F915: bita #as_mjmn ; minor mode? bne loc_F91E ; yes, ignore that lda #1 ; send last byte EOI jsr gpib_sendbyte_with_eoi loc_F91E: lds #stacktop ; reset stack jmp mainloop ; ignore incoming bytes until EOI drain_read: jsr gpib_readbyte ; read byte bcs loc_F92C ; CY=1, error bvc drain_read ; not yet EOI, loop loc_F92C: lds #stacktop ; and reset jmp mainloop ;============================================= ; check whether device is fully initialized assert_dsj_not_2: ldb dsj ; get DSJ cmpb #2 ; is it still in init state? beq loc_F8FB ; yes, signal error rts ; otherwise exit ;============================================= amigo_illopcode: lda #1 ; set illegal opcode status sta s1_errcode ;============================================= amigo_errorexit: lda #1 ; DSJ=error sta dsj jsr gpib_set_PP ; parallel poll jsr led_on ; switch on LED jmp drain_read ; drain bytes to read ;============================================= gpib_validsecondary: lda #auxm_v_sa ; signal valid secondary address sta gpib_auxm rts ;============================================= gpib_invalidsecondary: lda #auxm_nv_sa ; signal invalid secondary sta gpib_auxm rts ;============================================= ; issue enable parallel poll gpib_set_PP: lda #auxm_set_pp sta gpib_auxm rts ;============================================= ; issue disable parallel poll gpib_clr_PP: lda #auxm_clr_pp sta gpib_auxm rts ;============================================= ; read from GPIB until UNLISTEN, EOI or SECONDARY ; set APT flag if secondary pending (return in A) ; set V if ended with EOI ; set C if byte in, but not listener (protocol or hardware error) gpib_readbyte: andcc #~cc_c ; clear CY lda gpib_ad01 ; get interrupt flag bpl loc_F979 ; no interrupt, skip lda gpib_int1 ; get interrupt status bita #ints1_bi ; byte in interrupt? beq loc_F983 ; no, skip bita #ints1_apt ; verify secondary? beq loc_F9A3 ; no, skip lda #1 ; notify APT pending sta gpib_apt_flag bra loc_F9A3 ; continue ; interrupt from GPIB pending loc_F979: lda gpib_ad01 ; get interrupt again, was spurious? bpl loc_F992 ; yes, ignore it lda gpib_int1 ; no, this one's for real ; get interrupt status bita #ints1_bi ; byte in interrupt? bne loc_F99A ; yes, skip loc_F983: bita #ints1_dec ; device clear received? lbne do_dcas ; yes handle it bita #ints1_apt ; verify secondary? beq loc_F992 ; no, ignore it lda #1 ; notify APT pending sta gpib_apt_flag loc_F992: lda gpib_am ; get address mode bita #as_la ; is listener addressed? beq loc_F9B1 ; no, skip bne loc_F979 ; loop to drain bytes to listen for loc_F99A: bita #ints1_apt ; verify secondary? beq loc_F9A3 ; no, skip lda #1 ; notify APT pending sta gpib_apt_flag ; just BYTE IN interrupt, get byte loc_F9A3: lda gpib_am ; just byte in interrupt, get byte bita #as_eoi ; EOI seen? (clears V) beq loc_F9AE ; no, return data byte with V=0 lda gpio_dio ; yes, return data byte with V=1 orcc #cc_v rts loc_F9AE: lda gpio_dio ; just return data byte with V=0 rts loc_F9B1: orcc #cc_c ; set CY=1, end of listen lda gpio_dio ; read data byte rts ;============================================= ; send a databyte through GPIB gpib_sendbyte: pshs a ; save byte to send gpib_sendbyte1: lda gpib_ad01 ; get GPIB int flag bpl loc_F9CD ; no interrupt lda gpib_int1 ; get interrupt status bita #ints1_bo ; byte out interrupt? beq loc_F9D7 ; no, skip bita #ints1_apt ; APT interrupt? beq loc_F9FA ; no, go sending lda #1 ; flag APT interrupt sta gpib_apt_flag bra loc_F9FA ; go sending loc_F9CD: lda gpib_ad01 ; get GPIB int flag bpl loc_F9E8 ; no interrupt? skip lda gpib_int1 ; get interrupt status bita #ints1_bo ; byte out interrupt? bne loc_F9FA ; yes, go sending loc_F9D7: bita #ints1_dec ; device clear interrupt? lbne do_dcas ; yes, reset bita #ints1_apt ; APT interrupt? beq loc_F9E8 ; no, skip lda #1 ; flag APT interrupt sta gpib_apt_flag bra loc_F9F2 ; send unsuccessful loc_F9E8: lda gpib_am ; get mode register bita #as_ta ; is device addressed as talker? beq loc_F9F2 ; no, send unsuccessful bita #as_mjmn ; minor mode? beq loc_F9CD ; no, loop ; minor mode or other error: send unsuccessful loc_F9F2: puls a ; restore byte to send clr eoi_flag orcc #cc_c ; set carry flag (unsuccessful) rts loc_F9FA: puls a ; restore byte to send tst eoi_flag ; check if send with EOI beq loc_FA08 ; no, don't EOI ldb #6 ; set EOI on data output stb gpib_auxm clr eoi_flag loc_FA08: sta gpio_dio ; put byte out on DIO andcc #~cc_c ; clear CY (success) rts ;============================================= ; send a byte with EOI set gpib_sendbyte_with_eoi: pshs a ; save byte to send lda #1 sta eoi_flag ; send byte with EOI bra gpib_sendbyte1 ; go send data ;============================================= ; delay, A is number of seconds to delay delay: ldx #58824 ; load timing value loc_FA19: jsr nullsub_1 ; waste time jsr nullsub_1 ; waste more time leax -1,x ; decrement X bne loc_FA19 ; loop deca ; decrement A bne delay ; more delay rts ; done ;============================================= switch on LED for 5 seconds led_on5sec: ldb portctrl_state ; switch on LED orab #ctrl_led stb portctrl_state stb portcc lda #5 ; wait 5 seconds jsr delay andb #~ctrl_led ; switch off LED stb portctrl_state stb portcc rts ;============================================= ; NMI is used for service initiated self test ; shorten jumper on board, select test to be done by ; address switches nmi_vector: lds #stacktop ; load stack lda statuscc ; get status port bita #status_test ; testsw set? lbne loc_FADE ; test jumper is 1 jsr led_on5sec ; switch on LED for 5sec selftest_loop: lda statuscc ; get status port anda #7 ; mask address switches bne loc_FA63 ; not zero, skip jsr selftest_chk_ram ; TEST 0: check RAM bcs selftest_error_5sec ; signal failure ldb #1 ; blink LED once jsr blink_led bra loc_FAD2 ; reinitialize loc_FA63: cmpa #1 ; TEST 1: check ROM bne loc_FA73 ; no, skip jsr selftest_chk_rom ; do test bcs selftest_error_5sec ; signal failure ldb #2 ; blink twice for success jsr blink_led bra loc_FAD2 ; reinitialize loc_FA73: cmpa #2 ; TEST 2: check GPIB chip bne loc_FA83 ; no, skip jsr selftest_check_gpib ; do test bcs selftest_error_5sec ; signal failure ldb #3 ; blink 3 times for success jsr blink_led bra loc_FAD2 ; reinitialize loc_FA83: cmpa #3 ; TEST 3: check FDC chip bne loc_FA93 ; no, skip jsr selftest_chk_fdc ; do test bcs selftest_error_5sec ; signal failure ldb #4 ; blink 4 times jsr blink_led bra loc_FAD2 ; reinitialize loc_FA93: cmpa #5 ; TEST 5: check motor speed bne loc_FAA3 ; no, skip jsr selftest_chk_motor ; do test bcs selftest_error_5sec ; signal failure ldb #6 ; blink 6 times jsr blink_led bra loc_FAD2 ; reinitialize loc_FAA3: cmpa #4 ; TEST 4: seek test bne loc_FAB3 ; no, skip jsr selftest_chk_seek ; do test bcs selftest_error_5sec ; signal failure ldb #5 ; blink 5 times for success jsr blink_led bra loc_FAD2 ; reinitialize loc_FAB3: cmpa #6 ; TEST 6: format test bne loc_FAC3 ; no, skip jsr selftest_chk_format ; do test bcs selftest_error_5sec ; signal failure ldb #7 ; blink 7 times jsr blink_led bra loc_FAD2 ; reinitialize loc_FAC3: jsr selftest_chk_verify ; TEST 7: read/verify test bcs selftest_error_5sec ; signal failure ldb #8 ; blink 8 times jsr blink_led bra loc_FAD2 ; reinitialize selftest_error_5sec: jsr led_on5sec ; switch on LED for 5 sec to signal failure of test ; arrive here after test, check for loop mode loc_FAD2: lda statuscc ; read status port bita #status_loop ; loop mode? lbeq selftest_loop ; yes, repeat test jmp initialize_all ; reinitialize loc_FADE: jsr selftest_chk_ram ; check the RAM bcs loc_FB26 ; failed, skip jsr selftest_chk_rom ; check the ROM bcs loc_FB26 ; failed, skip jsr selftest_check_gpib ; check GPIB chip bcs loc_FB26 ; failed, skip jsr selftest_chk_fdc ; check FDC chip bcs loc_FB26 ; failed, skip ldu #0 ; select drive 0 stu drive_ptr jsr fdc_waitrdy_select_curdrv : waiting for being ready jsr fdc_spinup ; start motor lda statuscc ; get status port bmi loc_FB1E ; no disk in drive, skip jsr selftest_chk_seek ; check seek bcs loc_FB26 ; failed, skip jsr selftest_chk_motor ; check motor speed bcs loc_FB26 ; failed, skip jsr selftest_chk_format ; check formatting bcc loc_FB19 ; succeeded, continue lda fdc_status ; get drive status bita #0x40 ; was write protect? beq loc_FB26 ; no, failed, skip loc_FB19: jsr selftest_chk_verify ; verify formatted disk bcs loc_FB26 ; failed, skip loc_FB1E: ldb #0xA ; blink LED 10 times jsr blink_led jmp initialize_all ; initialize loc_FB26: jsr led_on5sec ; failure: set LED on for 5 seconds jmp initialize_all ; initialize ;============================================= ; test RAM, if okay CY=0, if error CY=1 selftest_chk_ram: ldx #diskbuf ; load RAM base clra ; clear A loc_FB30: sta ,x+ ; clear memory inca ; increment stored value cmpx #chkram_top ; check whether close to stack top bne loc_FB30 ; no loop ldx #diskbuf ; load base of ram again clra ; clear A loc_FB3C: cmpa ,x+ ; check whether RAM was set correctly bne loc_FB72 ; no, error inca ; next cell value cmpx #chkram_top ; end of checked RAM bne loc_FB3C ; loop ldx #diskbuf ; load RAM base lda #0xFF ; load FF loc_FB4B: sta ,x+ ; store in RAM deca ; decrement stored value cmpx #chkram_top ; end of checked ram reached? bne loc_FB4B ; no, loop ldx #diskbuf ; load RAM base lda #0xFF ; load check value loc_FB58: cmpa ,x+ ; test if okay bne loc_FB72 ; no error deca ; decrement value to check cmpx #chkram_top ; end of ram reached? bne loc_FB58 ; no loop ldx #gpio_dio ; load memory base loc_FB65: clr ,x+ ; clear memory cmpx #chkram_top ; until end of checked RAM bne loc_FB65 ; loop andcc #~1 ; clear CY jsr led_off ; switch off LED rts ; exit loc_FB72: orcc #1 ; set carry rts ; exit ;============================================= selftest_chk_rom: ldx #0xE000 ; load ROM BASE ldd #0 ; clear accu (checksum) loc_FB7B: addb ,x+ ; add byte of ROM bcc loc_FB80 ; if no carry, skip inca ; increment higher byte of checksum loc_FB80: cmpx #0 ; end of ROM reached? bne loc_FB7B ; no loop std temp1 ; store ROM checksum ldd rom_checksum ; check checksum to reach clra ; only low byte std temp4 ; save it ldd temp1 ; get checksum subd temp4 ; subtract low byte std temp1 ; store it again ldd rom_checksum ; get high byte of checksum to reach clrb exg a, b ; make it low value std temp4 ; store it ldd temp1 ; subtract it from checksum subd temp4 cmpd rom_checksum ; is it the correct ROM checksum? bne loc_FBB0 ; no, set carry andcc #~cc_c ; clear CY rts ; exit loc_FBB0: orcc #cc_c ; set CY for error rts ;============================================= selftest_check_gpib: lda #0x55 ; store pattern in address sta gpib_ad01 cmpa gpib_ad01 ; check if it can be read out bne loc_FBD9 ; no, exit with CY=1 (error) lda #0x2A sta gpib_ad01 ; initialize LISTEN 0x0a cmpa gpib_ad01 ; check if this can be set bne loc_FBD9 ; no, exit with error lda #0xC0 ; set mode to talk to itself sta gpib_am clr gpib_ad01 ; select address 0 clr gpib_auxm ; set immediate PON clra loc_FBCC: sta gpio_dio ; send data byte 0 nop ; wait cmpa gpio_dio ; check that it can be received again bne loc_FBD9 ; no, exit with error inca ; increment byte bne loc_FBCC ; loop 256 times andcc #~cc_c ; exit okay rts loc_FBD9: orcc #cc_c ; exit error rts ;============================================= ; verify that FDC is present and some regs are writeable selftest_chk_fdc: lda #0x55 ; load some ill value into FDC track register sta FDC_port.tr coma ; complement into sector register sta FDC_port.scr jsr nullsub_1 ; wait a bit cmpa FDC_port.scr ; compare it with stored value bne loc_FC0B ; not the same, exit CY=1 (error) coma ; complement cmpa FDC_port.tr ; compare with track register bne loc_FC0B ; not okayx, error sta FDC_port.scr ; do the same again with reversed bits coma sta FDC_port.tr jsr nullsub_1 cmpa FDC_port.tr bne loc_FC0B ; not okay, error coma cmpa FDC_port.scr ; not okay, error bne loc_FC0B andcc #~cc_c ; clear CY (no error) rts loc_FC0B: orcc #cc_c rts ;============================================= ; check that track 0 can be correctly reached ; return CY=1 if error, 0 if success selftest_chk_seek: ldu #0 ; select drive 0 stu drive_ptr loc_FC14: jsr fdc_waitrdy_select_curdrv ; wait for disk ready jsr fdc_restore_trk0 ; move to track0 bcs loc_FC4F ; failed, continue lda #fdcmd_restore ; issue RESTORE again sta FDC_port.str_cr jsr fdc_waitrdy ; wait until done lda FDC_port.str_cr ; get status bita #fdc_status1_trk0 bne loc_FC62 ; is track 0 not reached? (negative logic!) ; goto error lda #69 ; position to last track coma sta FDC_port.dr ; target position lda #fdcmd_seek sta FDC_port.str_cr ; issue SEEK command jsr fdc_waitrdy ; wait until done lda FDC_port.str_cr ; get status bita #fdc_status1_trk0 ; is track 0 reached? beq loc_FC62 ; oops, this is reversed? error lda #fdcmd_restore ; issue RESTORE sta FDC_port.str_cr jsr fdc_waitrdy ; wait until done lda FDC_port.str_cr bita #fdc_status1_trk0 ; is track 0 not reached? bne loc_FC62 ; oops, this is reversed? loc_FC4F: inc drive_ptr+1 ; increment drive pointer ldu drive_ptr ; select drive lda #2 ; loop over all drives cmpa drive_ptr+1 bne loc_FC14 ; loop jsr fdc_select_drv0 ; select drive 0 andcc #~cc_c ; return CY=0 rts loc_FC62: jsr fdc_select_drv0 ; select drive 0 orcc #cc_c ; return with error rts ;============================================= ; check if motor speed on track 36 is within valid limits ; exit CY=1 if error ; requires disk in drive to be checked, ; will return success if no disk in drive ; (power on selftest with no disks in drives) selftest_chk_motor: ldu #0 ; select drive 0 stu drive_ptr loc_FC6E: jsr fdc_waitrdy_select_curdrv ; wait until drive ready jsr fdc_spinup ; start motor jsr fdc_loadhead ; load head jsr fdc_restore_trk0 ; move to track 0 bcs loc_FC8F ; if error, skip lda #35 ; position to track 35 coma sta FDC_port.dr lda #fdcmd_seek ; issue SEEK sta FDC_port.str_cr jsr fdc_waitrdy ; wait until done jsr fdc_checkmotorspeed ; check speed of motor in valid range bcs loc_FCA5 ; if not, exit failure loc_FC8F: inc drive_ptr+1 ; advance to next drive ldu drive_ptr lda #2 cmpa drive_ptr+1 ; all drives done? bne loc_FC6E ; no, loop jsr fdc_motoroff ; switch off motor jsr fdc_select_drv0 ; select drive 0 andcc #~cc_c ; exit with success rts loc_FCA5: jsr fdc_motoroff ; switch off motor jsr fdc_select_drv0 ; select drive 0 orcc #cc_c ; exit with error rts ;============================================= ; return CY=0 if revolution speed is okay fdc_checkmotorspeed: ldx #0 ; set counter loc_FCB1: leax -1,x ; decrement X beq loc_FCF2 ; if zero reached, return CY=1 lda FDC_port.str_cr ; get fdc status anda #fdc_status1_index ; index pulse found? beq loc_FCB1 ; no, loop ldx #0 ; reset counter loc_FCBF: leax -1,x ; decrement beq loc_FCF2 ; if zero reached, return CY=1 lda FDC_port.str_cr ; get fdc status anda #fdc_status1_index ; still index pulse bne loc_FCBF ; yes, wait until zero ldx #22500 ; load count for speed loc_FCCD: leax -1,x ; decrement bne loc_FCCD ; wait some time ;============================================= fdc_measure_speed: ldx #0 ; clear counter loc_FCD4: jsr nullsub_1 ; wait some time jsr nullsub_1 leax 1,x ; increment beq loc_FCF2 ; overrun, exit CY=1 lda FDC_port.str_cr ; get fdc status anda #fdc_status1_index ; check index pulse bne loc_FCD4 ; is still one cmpx #314 ; is time to index pulse between 314 and 584 bls loc_FCF2 cmpx #584 bcc loc_FCF2 andcc #~cc_c ; yes, okay, return CY=0 rts loc_FCF2: orcc #cc_c ; return CY=1 rts ;============================================= ; format all disks in drives ; return CY=1 if failure, 0 if success selftest_chk_format: ldu #0 ; select drive 0 stu drive_ptr loc_FCFB: jsr fdc_waitrdy_select_curdrv ; wait for disk ready jsr fdc_spinup ; start motor jsr fdc_restore_trk0 ; go to track 0 bcs loc_FD19 ; if error, continue with next drive jsr delay_5000 ; wait some time clr format_filler ; filler pattern = 0 lda #1 sta format_interleave ; set interleave=1 sta override_old_fmt ; set override flag jsr fdc_format_disk ; format entire disk bne loc_FD2F ; if error, exit loc_FD19: inc drive_ptr+1 ; increment drives to test ldu drive_ptr lda #2 cmpa drive_ptr+1 ; last drive? bne loc_FCFB ; no, loop jsr fdc_motoroff ; switch off motor jsr fdc_select_drv0 ; select drive 0 andcc #~cc_c ; return with success rts loc_FD2F: sta fdc_status ; store error data jsr fdc_motoroff ; switch off motor jsr fdc_select_drv0 ; select drive 0 orcc #cc_c ; exit with error rts ;============================================= ; ensure all sectors of disk are readable without error selftest_chk_verify: ldu #0 ; start with drive 0 stu drive_ptr loc_FD41: jsr fdc_waitrdy_select_curdrv ; select drive jsr fdc_spinup ; start motor jsr fdc_restore_trk0 ; go to track 0 bcs loc_FD66 ; if error, continue with next drive jsr delay_5000 ; wait some time clr drvN_tgthead,u ; position target to 0,0,0 clr drvN_tgtcylinder,u clr drvN_tgtsector,u clr verify_seccnt ; clear sector count clr verify_seccnt+1 jsr verify_sectors ; verify all sectors can be read bne loc_FD7C ; if error, exit loc_FD66: inc drive_ptr+1 ; advance to next drive ldu drive_ptr lda #2 cmpa drive_ptr+1 ; last drive? bne loc_FD41 ; no, loop jsr fdc_motoroff ; switch off motor jsr fdc_select_drv0 ; select drive 0 andcc #~cc_c ; return with CY=0, success rts loc_FD7C: jsr fdc_motoroff ; switch of motor jsr fdc_select_drv0 ; select drive 0 orcc #cc_c ; return with error rts ;============================================= ; undocumented command ; listen 0c 1a ; formats the boot track with various patterns ; to ensure it is correct ; then expects a listen 02 and a sector number ; and 256 data bytes to be written into the ; specified sector. Verifies correct writing. ; continue over all sectors of the disk until end of disk ; ; this is supposedly an HP internal command to ; fill an entire disk with data. amigo_writedisk: jsr gpib_readbyte ; get unit byte lbcs gpib_errorstate ; if error, exit jsr chk_validunit ; check if valid unit sta selected_unit ; select it jsr gpib_readbyte ; get another byte lbcs gpib_errorstate ; if error, exit clr gpib_apt_flag ; clear flag "secondary pending" cmpa #0xF ; is byte >15? yes error lbhi gpib_errorstate sta format_specinterleave ; store it jsr gpib_clr_PP ; disable parallel poll clr dsj ; set success flag jsr fdc_waitrdy_select_curdrv ; wait for disk jsr fdc_spinup ; start motor clra sta drvN_activehead,u ; clear known position sta drvN_activecyl,u sta drvN_curhead,u ; clear reported position sta drvN_curtrk,u sta drvN_tgtcylinder,u ; clear target to go to sta drvN_tgthead,u coma ; negative logic sta FDC_port.tr ; store into track regeister lda #fdcmd_restore sta FDC_port.str_cr ; issue RESTORE (to track 0) command jsr fdc_waitrdy ; wait until done loc_FDD6: jsr delay_5000 ; wait some time lda #1 sta fmtcnt ; take filler 1 from table sta sys_state ; set state=1 loc_FDE1: lda drvN_tgtcylinder,u ; set parameters for formatting this track sta format_cylinder lda drvN_tgthead,u sta format_head lda #1 ; set interleave 1 sta format_interleave lda fmtcnt ; get pattern to use sta trkpattern+1 ; make a 16 bit index clr trkpattern ldx trkpattern lda track_fillers,x ; get filler byte sta format_filler ; set it as fill byte jsr fdc_format ; format the first track with interleave 1 beq loc_FE14 ; if no error, continue jsr set_s2_error ; set error codes lda #1 ; set unsuccessful sta dsj loc_FE14: clr drvN_tgtsector,u ; :start at sector 0 loc_FE18: jsr fdc_readsector ; verify sector beq loc_FE25 ; was okay, skip jsr set_s2_error ; otherwise set error ocdes lda #1 ; set unsuccessful sta dsj loc_FE25: lda drvN_tgtsector,u ; loop over alls sectors of track cmpa #15 beq loc_FE33 ; done inc drvN_tgtsector,u ; next sector bra loc_FE18 ; loop loc_FE33: dec fmtcnt ; take next pattern bpl loc_FDE1 ; still positive, retry with other pattern lda format_specinterleave ; get actual interleave to use sta format_interleave ; store it lda drvN_tgtcylinder,u ; get target cylinder sta format_cylinder ; set format parameters lda drvN_tgthead,u sta format_head jsr fdc_format ; format that track again beq loc_FE59 ; if not error, continue jsr set_s2_error ; set error lda #1 sta dsj loc_FE59: lda #0xF ; set count of 15 sta fmtcnt jsr gpib_set_PP ; set parallel poll loc_FE61: lda gpib_ad01 ; check GPIB interrupt bpl loc_FE61 ; wait until one happens lda gpib_int1 ; get int status bita #ints1_apt ; verify other secondary? lbeq gpib_errorstate ; no, error lda gpib_auxm ; get mode anda #~as_ton ; mask bits cmpa #0x62 ; is it secondary 2? beq loc_FE7B ; yes, continue jsr gpib_invalidsecondary ; no, do not accept more jmp gpib_errorstate ; go to error state loc_FE7B: jsr gpib_validsecondary ; acknowledge valid secondary loc_FE7E: lda gpib_ad01 ; wait for GPIB interrupt bpl loc_FE7E lda gpib_int1 ; get interrupt status bita #ints1_bi ; byte in pending? lbeq gpib_errorstate ; no, error lda gpio_dio ; get data byte sta drvN_tgtsector,u ; set as target sector ldx #0 ; set start of buffer loc_FE93: lda gpib_ad01 ; wait for GPIB interrupt bpl loc_FE93 lda gpib_int1 ; get int status bita #ints1_bi ; byte in pending? lbeq gpib_errorstate ; no, error ldb gpio_dio ; Get data byte stb ,x+ ; store in buffer cmpx #end_buf ; end of buffer reached? bne loc_FE93 ; no, loop jsr fdc_write_sector ; write this sector to disk beq loc_FEB5 ; no error, continue jsr set_s2_error ; set error flags lda #1 ; set unsuccessful sta dsj loc_FEB5: dec fmtcnt ; decrement count of sectors bpl loc_FE7E ; loop over 16 sectors jsr gpib_clr_PP ; disable parallel poll clra ldb #0xF std cnt16 ; set 16bit counter to 16 loc_FEC3: ldx cnt16 ; get counter lda sector_numbers,x ; get sector number table sta drvN_tgtsector,u ; set as sector to verify jsr fdc_readsector ; verify the given sector beq loc_FEDB ; yes, continue jsr set_s2_error ; set error code lda #1 ; set unsuccessful sta dsj loc_FEDB: dec cnt16+1 ; decrement loop bpl loc_FEC3 ; loop over all sectors to verify jsr fdc_nextsector1 ; Advance to next sector tst drvN_endofdisk,u ; end of disk reached? bne loc_FEFF ; yes, skip jsr fdc_stepin ; go to next cylinder lda drvN_tgtcylinder,u ; copy target position into track register adda drvN_tgtcylinder,u adda drvN_tgthead,u coma sta FDC_port.tr jmp loc_FDD6 ; loop over all tracks loc_FEFF: jsr fdc_restore_trk0 ; return to track 0 jsr delay_5000 ; wait some time lda #0xE7 sta drvN_wearh,u ; set a high value into wear level clra sta drvN_wearm,u sta drvN_wearl,u sta gpib_int1 ; clear GPIB interrupts sta sys_state ; set state = 0 jsr write_sector17 ; write wear level into sector 17 jsr gpib_set_PP ; enable parallel poll tst dsj ; were there errors? beq locret_FF2A ; no, exit lda #1 ; mark disk as worn out sta drvN_disk_wornout,u locret_FF2A: rts ; exit track_fillers: .db ~0xA4 .db ~0 ;============================================= delay_5000: ldx #5000 ; waste some time loc_FF30: leax -1,x bne loc_FF30 rts ;============================================= ; undocumented ; listen 1d ; 00: go to trk0, then step in # of tracks ; accept three pattern bytes and fill selected ; track with it ; ; 01: go to trk0, then step in # of tracks ; 02: step in unit # of tracks ; 03: step out unit # of tracks ; ; supposedly HP internal diagnostic amigo_diagnostic: jsr gpib_validsecondary ; acknowledge valid secondary jsr gpib_readbyte ; get opcode byte lbcs gpib_errorstate ; if error, exit cmpa #3 ; is it >3? yes illegal opcode lbhi amigo_illopcode sta fdc_status ; save temporary jsr gpib_readbyte ; get unit byte lbcs gpib_errorstate ; if error, exit jsr chk_validunit ; check valid unit jsr fdc_waitrdy_select_curdrv jsr fdc_spinup ; start motor lda fdc_status ; get opcode beq stepdiag_op01 ; if 0 or 1, continue cmpa #1 beq stepdiag_op01 cmpa #2 ; if opcode=2, skip beq stepdiag_op2 jsr gpib_readbyte ; opcode is 3, get step count lbcs gpib_errorstate ; if error, exit tfr a, b ; move to B as count loc_FF6E: decb ; decrement count bmi stepdiag_done ; if negative, skip jsr fdc_movetrack_out ; step towards track 0 bra loc_FF6E ; loop stepdiag_op2: jsr gpib_readbyte ; opcode is 2, get step count lbcs gpib_errorstate ; if error, exit tfr a, b ; move to B as count loc_FF7F: decb ; decrement count bmi stepdiag_done ; if negative, skip jsr fdc_movetrack_in ; step towards track 69 bra loc_FF7F ; loop stepdiag_op01: jsr fdc_loadhead ; load head jsr fdc_restore_trk0 ; move to track 0 bra stepdiag_op2 ; step n steps forward stepdiag_done: lda fdc_status ; get opcode bne loc_FFB5 ; is not zero? jsr gpib_readbyte ; get another byte lbcs gpib_errorstate ; is error? sta fdc_status ; store 1st byte jsr gpib_readbyte ; get another byte lbcs gpib_errorstate ; if error, exit sta temp3 ; store 2nd byte jsr gpib_readbyte ; get 3rd byte lbcs gpib_errorstate sta temp1 ; save it jsr write_diagpattern ; fill track with given diagnostic patterns loc_FFB5: jsr gpib_readbyte ; get a (EOI) byte from GPIB and exit rts ;============================================= ; diag is called from undocumented diagnostic function ; this fills the specified track with ; a triple of alignment patterns in fdc_status, temp3 and temp1 write_diagpattern: clra sta gpib_int1 ; disable GPIB interrupt sta sys_state ; set state = 0 lda FDC_port.str_cr ; drain FDC status andcc #~cc_firq ; enable FIRQ lda portctrl_state oraa #ctrl_halten ; enable HALTEN sta portcc ldb #fdcmd_writetrk ; issue write track command stb FDC_port.str_cr sta portctrl_state loc_FFD4: lda fdc_status ; get first data byte coma nop sta FDC_port.dr ; store into data register lda temp3 ; get second data byte coma nop sta FDC_port.dr ; store into data register lda temp1 ; get second data byte coma nop sta FDC_port.dr ; store into data register bra loc_FFD4 ; loop until FIRQ ;============================================= .dw 0xFFFF .dw 0 .dw reset_vector ; SWI3_vector (unused) .dw reset_vector ; SWI2_vector (unused) .dw firq_vector ; handles interrupts from GPIB and FDC .dw irq_vector ; counts index pulses of spinning disk .dw reset_vector ; SWI vector (unused) .dw nmi_vector ; self test .dw reset_vector ; standard powerup