;;; ;;; MCFS2 Compact Flash formatter ;;; By: Daniel Tufvesson 2017 ;;; ;;; ;;; Monitor routines ;;; mon_return: equ $C000 ; return to monitor mon_outchar: equ $C003 ; outpur char in a on console mon_pdata: equ $C009 ; print text string at x ended by $04 mon_out4hs: equ $C015 ; print 4 hex chars at x mon_pcrlf: equ $C021 ; print crlf page_register: equ $0002 ; I/O page select register ;;; ;;; CF registers ;;; cf_base: equ $9fd0 cf_reg_0: equ cf_base+0 ; data port cf_reg_1: equ cf_base+1 ; read: error code, write: feature cf_reg_2: equ cf_base+2 ; number of sectors to transfer cf_reg_3: equ cf_base+3 ; sector address LBA 0 [0:7] cf_reg_4: equ cf_base+4 ; sector address LBA 1 [8:15] cf_reg_5: equ cf_base+5 ; sector address LBA 2 [16:23] cf_reg_6: equ cf_base+6 ; sector address LBA 3 [24:27 (LSB of reg)] cf_reg_7: equ cf_base+7 ; read: status, write: command ;;; ;;; CF commands ;;; cf_cmd_reset: equ $04 cf_cmd_read: equ $20 cf_cmd_write: equ $30 ;;; ;;; Program begin here ;;; org $0100 jmp format txt_hdr: fcc "Header = " fcb $04 txt_alloc: fcc " Alloc = " fcb $04 txt_root: fcc " Root = " fcb $04 txt_error: fcc "Error " fcb $04 ;;; ;;; Program variables ;;; media_addr_3: rmb 1 media_addr_2: rmb 1 media_addr_1: rmb 1 media_addr_0: rmb 1 ;;; ;;; MCFS2 format routine ;;; format: jsr mon_pcrlf ldaa #$f0 staa page_register jsr cf_init jsr cf_check_error beq *+5 jmp general_error ;;; Start of partition clr media_addr_3 clr media_addr_2 clr media_addr_1 clr media_addr_0 ;;; MCFS partition header sector ldx #txt_hdr jsr mon_pdata ldx #media_addr_1 jsr mon_out4hs jsr mon_pcrlf jsr clr_secbuf ldx #sector_buffer ldaa #'M ; "MCFS" staa vol_hdr+0 ldaa #'C staa vol_hdr+1 ldaa #'F staa vol_hdr+2 ldaa #'S staa vol_hdr+3 ldaa #$02 ; MCFS version $02 staa vol_ver ldx #$0000 ; Partition begin (this sector) stx vol_beg ldx #$ffff ; Partition end (last sector) stx vol_end ldx #$5555 ; Volume ID stx vol_id ldx #$0001 ; Sector allocation table begin stx vol_alloc_beg ldx #$0080 ; Sector allocation table end stx vol_alloc_end ldx #$0081 ; Root directory begin stx vol_root_beg ldx #$0088 ; Root directory end stx vol_root_end jsr write_sector ; Write sector jsr cf_check_error beq *+5 jmp general_error ;;; Allocation sectors ldx #txt_alloc jsr mon_pdata inc media_addr_0 ldx #media_addr_1 jsr mon_out4hs ;;; Allocation sector 1 (with 50 allocated sectors) jsr clr_secbuf clrb ldx #sector_buffer alloc_loop1: cmpb #138 bhi alloc_loop1_end inc ,x inx incb bra alloc_loop1 alloc_loop1_end: jsr write_sector ;;; Remaining 127 allocation sectors jsr clr_secbuf inc media_addr_0 clrb alloc_loop2: cmpb #125 bhi alloc_loop2_end jsr write_sector inc media_addr_0 incb bra alloc_loop2 alloc_loop2_end: ldaa #'- jsr mon_outchar ldaa #$20 jsr mon_outchar ldx #media_addr_1 jsr mon_out4hs jsr mon_pcrlf jsr cf_check_error beq *+5 jmp general_error ;;; Root directory ldx #txt_root jsr mon_pdata inc media_addr_0 ldx #media_addr_1 jsr mon_out4hs jsr clr_secbuf ; Write root directory sector 1 jsr write_sector inc media_addr_0 ; Write root directory sector 2 jsr write_sector inc media_addr_0 ; Write root directory sector 3 jsr write_sector inc media_addr_0 ; Write root directory sector 4 jsr write_sector inc media_addr_0 ; Write root directory sector 5 jsr write_sector inc media_addr_0 ; Write root directory sector 6 jsr write_sector inc media_addr_0 ; Write root directory sector 7 jsr write_sector inc media_addr_0 ; Write root directory sector 8 jsr write_sector ldaa #'- jsr mon_outchar ldaa #$20 jsr mon_outchar ldx #media_addr_1 jsr mon_out4hs jsr mon_pcrlf jsr cf_check_error beq *+5 jmp general_error jmp mon_return general_error: ldx #txt_error jsr mon_pdata jsr mon_pcrlf jmp mon_return ;;; ;;; Clear RAM sector buffer ;;; clr_secbuf: ldx #sector_buffer clr_secbuf_loop: cpx #sector_buffer+512 bhi clr_secbuf_end clr ,x inx bra clr_secbuf_loop clr_secbuf_end: rts ;;; ;;; Read sector at media_addr_[3:0] store at X ;;; Z set on OK read. Error code in A ;;; read_sector: ldx #sector_buffer jsr cf_wait jsr cf_set_lba ldaa #1 staa cf_reg_2 ; number of sectors to read ldaa #cf_cmd_read staa cf_reg_7 ; issue read command jmp cf_read_data ; read data routine rts ;;; ;;; Write sector at media_addr_[3:0] store at X ;;; Z set on OK write. Error code in A ;;; write_sector: ldx #sector_buffer jsr cf_wait jsr cf_set_lba ldaa #1 staa cf_reg_2 ; number of sectors to write ldaa #cf_cmd_write staa cf_reg_7 ; issue write command jmp cf_write_data ; write data routine rts ;;; ;;; Initialize CF ;;; cf_init: ldaa #$04 ; reset command staa cf_reg_7 jsr cf_wait ldaa #$E0 ; LBA3=0, MASTER, MODE=LBA staa cf_reg_6 ldaa #$01 ; 8-bit transfers staa cf_reg_1 ldaa #$EF ; set-feature command staa cf_reg_7 jsr cf_wait rts ;;; ;;; Wait for CF ready ;;; cf_wait: ldaa cf_reg_7 anda #$80 ; mask out BUSY bit cmpa #$00 bne cf_wait rts ;;; ;;; Check for CF error ;;; Z set on OK ;;; Error code in A ;;; bit 7 - Bad block detected ;;; bit 6 - Uncorrectable data error ;;; bit 5 - Media changed ;;; bit 4 - ID not found ;;; bit 3 - Aborted command ;;; bit 2 - Media change requested ;;; bit 1 - Track 0 not found ;;; bit 0 - Addressmask not found ;;; cf_check_error: ldaa cf_reg_7 anda #$01 ; mask out ERROR bit cmpa #0 beq cf_no_error ldaa cf_reg_1 rts cf_no_error: clra rts ;;; ;;; CF set LBA ;;; cf_set_lba: ldaa media_addr_0 ; LBA byte 0 staa cf_reg_3 ldaa media_addr_1 ; LBA byte 1 staa cf_reg_4 ldaa media_addr_2 ; LBA byte 2 staa cf_reg_5 ldaa media_addr_3 ; LBA byte 3 anda #%00001111 ; mask out LBA bits oraa #%11100000 ; set mode LBA and master device staa cf_reg_6 rts ;;; ;;; Read data from CF ;;; Z set on OK ;;; error code in A ;;; cf_read_data: jsr cf_wait ldaa cf_reg_7 anda #$08 ; mask out DRQ bit cmpa #$08 bne cf_read_data_e ldaa cf_reg_0 ; read data byte staa ,X inx jsr cf_check_error beq cf_read_data rts cf_read_data_e: clra rts ;;; ;;; Write data to CF ;;; Z set on OK ;;; error code in A ;;; cf_write_data: jsr cf_wait ldaa cf_reg_7 anda #$08 ; mask out DRQ bit cmpa #$08 bne cf_write_data_e ldaa ,X staa cf_reg_0 ; write data byte inx jsr cf_check_error beq cf_write_data rts cf_write_data_e: clra rts ;;; ;;; Sector buffer ;;; org $1000 sector_buffer: rmb 512 ;;; ;;; Volume header ;;; 512 bytes ;;; org sector_buffer vol_hdr: rmb 4 ; file system ID = "MCFS" vol_ver: rmb 1 ; file system version = $02 vol_beg: rmb 2 ; first sector of partition vol_end: rmb 2 ; last sector of partition vol_id: rmb 2 ; volume ID vol_name: rmb 32 ; volume label (zero terminated) vol_alloc_beg: rmb 2 ; first sector of allocation table vol_alloc_end: rmb 2 ; last sector of allocation table (up to 16 sectors) vol_root_beg: rmb 2 ; first sector of root dir vol_root_end: rmb 2 ; last sector of root dir ;;; ;;; rest of sector is set to zero ;;;