NOLIST ; This file is part of picide, ATA(PI) interface to PIC18 family MCUs. ; Copyright (C) 2004-5 Toby Thain, toby@telegraphics.com.au ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2 of the License, or ; (at your option) any later version. ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; You should have received a copy of the GNU General Public License ; along with this program; if not, write to the Free Software ; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA LIST TITLE picide SUBTITLE "Main program" ;; Version history ;; 16-Oct-2004: 0.1 - started by Toby ;; 23-Feb-2005: 1.0 - public release under GPL ; this module contains the PIC reset & interrupt vectors, and main program. ; main program currently: ; - initialises RS232 and IDE ; - probes one or two ATA(PI) devices (master, and slave if attached) ; - does some drive initialisation (e.g. sets standby/idle timer) ; - enters command monitor (see monitor.asm) #include "defs.inc" #include "idecmd.inc" #include "atapidefs.inc" extern init_rs232,putch,getch extern dumpsec,monitor,dumpid extern init_ide,ide_identify,ide_idle extern ide_lbacmd,ide_rdata,ide_wdata extern ide_probe,ide_atapiiddev,ide_checkerr extern time400ms,delay1ms,delay2ms extern idecmd,seccnt,feat,lba0,lba8,lba16,lba24 extern dasplo,dasphi extern atapi_read10,atapi_readcd,atapi_reqsense,atapi_modesense,atapi_zeropkt extern atapi_readcapacity,atapi_checkerr,atapipkt extern putdec,putdec16,puthex,dec16,hexdigit,rnd8,LFSRVALUEL extern init_tick,start_time,end_time global stop,checkerr,devtype,tick1khz ;;; DATA ------------------------------------------------- udata_acs cnt res 1 probecnt res 1 ; # devices to probe errcode res 1 loopcnt res 2 devtype res 2 ; device types, two entries is_cnt res 1 ; used by initsec temp res 2 tick1khz res 3 ; 1kHz interrupt driven tick count (if used) ;;; RESET vector -------------------------------------------- org 0 bra start ;;; interrupt vectors & service routines ---------------------------- org 0x8 ; high priority vector inthi: btfsc PIR1,TMR2IF ; was it ours? bra timer2int ; yes retfie org 0x18 ; low priority vector intlo: retfie org 0x40 ; service 1kHz tick interrupt (if used) timer2int: ; interrupt overhead: around 9 cycles per 10,000 bcf PIR1,TMR2IF ; clear timer int flag incf tick1khz ; bump tick counter bnc intdone incf tick1khz+1 bnc intdone incf tick1khz+2 ; 24-bit timer overflows every 4hrs 39mins approx intdone:retfie 1 ; restore Wreg, STATUS from fast register stack ;;; MAIN PROGRAM ----------------------------------------------- start: ;movlw b'00011111' ; watchdog timer enable, prescale 1:32768 ;movwf CONFIG2H clrf INTCON ; disable all interrupts IF 0 ; setup 1kHz tick interrupt call init_tick bsf RCON,IPEN ; enable interrupt priority bsf IPR1,TMR2IP ; make Timer2 high priority interrupt bsf INTCON,GIEH ; enable high priority interrupts ENDIF ; initialise serial and IDE call init_rs232 call init_ide ; returns # of possible devices in W (1 or 2) movwf probecnt _puts "\r\nPIC START\r\n\0" IF 0 ; debugging only - log time for DASP assert (IDE slave) _puts "DASP_ @ 25.6us x \0" movlw low (15625) addwf dasplo,w movwf dec16 movlw high (15625) addwfc dasphi,w movwf dec16+1 call putdec16 _crlf ENDIF IF 0 _puts "Probe \0" movf probecnt,w call hexdigit _crlf ENDIF clrf devtype+0 clrf devtype+1 movlw IDE_DRVHEAD_LBA|IDE_DEVICE1 ; default value for drive/head sel movwf lba24 ; select device 1 btfss probecnt,1 ; probe two? bra probe0 ; probe device 1 _putstr msg_probe _puts "1: \0" call ide_probe ; leaves device type in Wreg movwf devtype+1 probe0: ; probe device 0 bcf lba24,DEVBIT ; select device 0 _putstr msg_probe _puts "0: \0" call ide_probe ; leaves device type in Wreg movwf devtype+0 ; do any device initialisation movlw IDE_DRVHEAD_LBA ; default value for drive/head sel movwf lba24 ; select drive 0 movf devtype+0,w rcall initdev bsf lba24,DEVBIT ; select device 1 movf devtype+1,w rcall initdev _puts "\r\nReady\r\n\0" goto monitor ; get user commands ; we use this twice msg_probe: dw "Device \0" ;--------------------------------------------------------- stop: _puts "\r\nSTOP.\r\n\0" clrwdt bra $-2 ;--------------------------------------------------------- checkerr: addlw 0 ; set flags on W bz noerr movwf errcode _puts "Error \0" movf errcode,w call puthex _putchar ':' call ide_checkerr ;bra stop ;movf errcode,w noerr: return ;--------------------------------------------------------- initdev: xorlw DEV_ATA bnz notata ; ----- ATA-specific device init ; always set ATA drive's idle/standby timer _puts "Enbl standby\r\n\0" movlw 60 ; 5 minutes-ish call ide_idle rcall checkerr IF 0 ; test code to read ATA sectors movlw 5 movwf temp+1 clrf lba16 clrf lba8 clrf lba0 atatest: clrf temp incf lba8 movlw high (65536-10) movwf loopcnt+1 movlw low (65536-10) movwf loopcnt movwf LFSRVALUEL sec: _puts " Rd sec 0x\0" movlw 1 movwf seccnt ;call initsec ; pre-fill sector buffer, for debugging ;call rnd8 ; scramble high LBA address bits - ;movwf lba16 ; enable this to deliberately trigger Read errors. call rnd8 movwf lba8 call rnd8 movwf lba0 movf lba16,w call puthex movf lba8,w call puthex movf lba0,w call puthex _crlf ; lba24 already set up with LBA high bits = 0 ;_puts "lbacmd,\0" movlw IDE_CMD_READ call ide_lbacmd addlw 0 bnz oops ;_puts "rdata,\0" movlw 0 ; 256 words, seccnt already set call ide_rdata call ide_checkerr ; always check error ;_puts " ok\r\n\0" movlw 1;32 call dumpsec tstfsz temp bra notfst setf temp call start_time notfst: incf lba0 bra another oops: call ide_checkerr another: incf loopcnt bnz sec incf loopcnt+1 bnz sec call end_time decfsz temp+1 bra atatest ENDIF ; done with ATA specific init bra alldrives notata: xorlw DEV_ATAPI ^ DEV_ATA bz isatapi goto dunno ; ----- ATAPI specific device init isatapi: IF 0 retryms: _puts "\r\nMode Sense \0" call atapi_zeropkt movlw 0x2a ; CD-ROM Capabilities & Mechanical Status page movwf ATAPI_PAGECTL movlw high ATAPI_TRANSFER_MAX movwf ATAPI_LEN8 movlw low ATAPI_TRANSFER_MAX movwf ATAPI_LEN0 call atapi_modesense xorlw ATAPI_RETRY bz retryms call atapi_checkerr tstfsz WREG bra bad _puts "Capabilities:\0" ;movlw 2 ;call dumpsec BANKSEL secbuf ; note that mode page itself is preceded by the 8-byte "mode parameter header" movf secbuf+(8+5),w,1 _putstrbits "\000 UPC\000 ISRC\000 C2ptrs\000 RWD&C\000 RWsupp\000 DAaccu\000 CDDA\000" _crlf _puts "Max: \0" movff secbuf+(8+8),dec16+1 movff secbuf+(8+9),dec16 call putdec16 _puts "KB/s\r\n\0" bad: ENDIF IF 0 ; starting LBA movlw 1 movwf temp+1 #define NSEC -101 movlw NSEC movwf temp rcdretry: _putchar 'R' rcdloop: call atapi_zeropkt movlw b'001'<<2 movwf atapipkt+1 ; expected sector type movff temp+1,ATAPI_LBA8 movff temp,ATAPI_LBA0 movlw 1 movwf ATAPI_LEN0 movlw b'00010000' ; user data, no headers movwf atapipkt+9 ; flags movlw b'001' ; RAW subchannel movwf atapipkt+10 ; subchannel data selection ;movf temp+1,w ;call puthex ;movf temp,w ;call puthex ;_putchar '*' call atapi_readcd xorlw ATAPI_RETRY bz rcdretry ; retry command xorlw ATAPI_RETRY ; restore error code bnz bad ; some other error! movf temp,w xorlw NSEC bnz notfirst call start_time notfirst: ;_putchar '+' ;movlw 1 ;ATAPI_CDDASECTOR/16 ;call dumpsec incf temp bnz rcdloop _putchar '.' call end_time bra alldrives bad: call atapi_checkerr _puts "ReadCD error\r\n\0" bra alldrives ENDIF IF 1 ; ...try to read some random sectors ; first try sector 16 movlw 0 movwf temp clrf temp+1 clrf temp+2 movlw 4 movwf loopcnt movwf LFSRVALUEL loopread: retryread: _puts "\r\nATAPI Read Sec=0x\0" call atapi_zeropkt ;movf temp+2,w ;movwf ATAPI_LBA16 ;call puthex movf temp+1,w movwf ATAPI_LBA8 call puthex movf temp,w movwf ATAPI_LBA0 call puthex _crlf movlw 1 movwf ATAPI_LEN0 call atapi_read10 xorlw ATAPI_RETRY bz retryread xorlw ATAPI_RETRY ; restore error bnz nogood movlw 8 ;2048/16 call dumpsec domore: call rnd8 movff LFSRVALUEL,temp+1 call rnd8 movff LFSRVALUEL,temp decfsz loopcnt bra loopread bra alldrives nogood: _puts "ERROR\r\n\0" bra domore ENDIF bra alldrives alldrives: ; do stuff here for both ATA and ATAPI dunno: return ;--------------------------------------------------------- initsec: ; fill the sector buffer with decreasing byte values (pairs) ; just for something pretty to look at movwf is_cnt ; # of sectors in Wreg on entry lfsr 1,secbuf clrf cnt doword: movff cnt,POSTINC1 movff cnt,POSTINC1 decfsz cnt bra doword decfsz is_cnt bra doword return ;--------------------------------------------------------- end