; autoptr.asm 10/19/08 ; Boot an HP from USB using the HP/IDE/USB interface... ; ; If port F bit 2 is high then resets an area of memory used ; to determine if already run, then returns back to Paulmon. ; Otherwise, it checks the memory to see if it has run (setting ; it at the same time), if already run then jumps to the disk ; controller code as usual. If not run or was reset with PF2 high ; then checks for a file named "BOOT" on the USB drive and if it ; exists sends it to the HP and waits for reset to be pressed, ; afterwards it resumes being a disk controller, unless the ; power is cycled, or if reset with PF2 high then reset again ; with PF2 low and the BOOT file present. ; ; Kind of funny way to do it but the default mode is exactly ; the sequence I want (boot the machine after powering up then ; stop doing that upon further resets), with an easy way to get ; it back into boot mode if I need to reboot. If I don't want to ; boot on power up I simply pull the thumbdrive or press reset. ; .equ port2base,0xF900 .equ locat,0xE000 .org locat .db 0xA5,0xE5,0xE0,0xA5 ;signiture bytes .db 253,255,0,0 ;id, 253=startup 35=don't start .db 0,0,0,0 .db 0,0,0,0 .db 0,0,0,0 .db 0,0,0,0 .db 0,0,0,0 ;user defined .db 255,255,255,255 ;length and checksum (255=unused) .db "Auto PTR",0 .org locat+64 .equ MemCheck, 0x7FF8 mov dptr,#port2base+3 ;ports D-F control register mov a,#0x93 ;D and E input, F 0-3 input 4-7 output movx @dptr,a mov dptr,#port2base+2 ;port F data register movx a,@dptr anl a,#00000100b ;mask bit 2 jz auto_switch_set ;switch not set, so clear the check memory to permit ;booting again when switch is set... clr a mov dptr,#MemCheck movx @dptr,a inc dptr movx @dptr,a inc dptr movx @dptr,a inc dptr movx @dptr,a inc dptr movx @dptr,a inc dptr movx @dptr,a ;and return to Paulmon... ret auto_switch_set: lcall BootTheThing ;first time boots/locks, after reset returns lcall USBsync ;clear out rest of boot file ljmp 0x8040 ;run the disk controller code ;---------------------------------------------------------- ;Scarfed from hpideusb.asm version 10/18/08 .equ hp_porta, port2base+0 .equ hp_portb, port2base+1 .equ hp_portc, port2base+2 .equ hp_config, port2base+3 .equ tmp, 0x18 ;temporary value .equ p1_buf, 0x20 ;port1 state variable .equ hp_lsb, 0x26 ;HP interface data buffer lsb .equ hp_msb, 0x27 ;HP interface data buffer msb ;--------------------------------------------------------------- ; HP hardware interface functions ck_bus: ; clock bus0-15 into hp data registers mov a, p1_buf ;get port1 state orl a, #00100000b ;and latch data bit mov p1, a ;send to port1 mov a, p1_buf ;get port1 state mov p1, a ;restore original port1 state ret ;return ;---------------------------------------------------------------- ck_flg: ; clock the flag flip flop on hp interface board mov a, p1_buf ;get port1 state orl a, #10000000b ;or-in hp flag bit mov p1, a ;send to port1 mov a, p1_buf ;get port1 state mov p1, a ;restore original port1 state ret ;return ;----------------------------------------------------------------- w_cmd: ; wait for command signal from hp interface board mov dptr, #hp_portc ;get hp 8255 port c address w_cmd1: ;keep checking for hp_cmd movx a, @dptr ;read hp 8255 port c anl a, #00000010b ;mask hp-command signal jz w_cmd1 ;is hp_cmd asserted? ret ;yes, we are done ;----------------------------------------------------------------- ide_2_hp: ; send a word to the hp interface with handshaking ; the 16-bit word to be sent must be in the hp_msb ; and hp_lsb data buffers. ; save contents of dptr push dpl ;save low byte of dptr push dph ;save high byte of dptr ; clear d_data bit so 8255 can drive bus0-15 mov a, p1_buf ;get port1 state anl a, #10111111b ;clear d_data bit mov p1_buf, a ;save new port1 state mov p1, a ;send new value to port1 ; configure 8255 to drive bus0-15 mov dptr, #hp_config ;get hp 8255 config address mov a, #10000001b ;get output config byte (mod for SPI) movx @dptr, a ;write it to the config port ; wait for device command signal from hp interface lcall w_cmd ;wait for cmd function ; send the word to bus0-15 mov dptr, #hp_porta ;get hp 8255 port a address mov a, hp_lsb ;get lsb of 16-bit word movx @dptr, a ;send it to hp 8255 port a mov dptr, #hp_portb ;get hp 8255 port b address mov a, hp_msb ;get msb of 16-bit word movx @dptr, a ;send it to hp 8255 port b ; clock the data into the hp data registers lcall ck_bus ;pulse the l_data signal ; complete the transfer by clocking flag lcall ck_flg ;clock flag to clear hp_cmd ; restore contents of dptr pop dph ;restore high byte of dptr pop dpl ;restore low byte of dptr ret ;end of ide_2_hp ;----------------------------------------------------------- ; USB functions .equ spicon, port2base+3 ;control register for SPI port .equ spiport, port2base+2 ;data register for SPI port .equ spiconv, 0x93 ;control value to access SPI port .equ spidi, 00001000b ;AND mask for read data bit .equ spido1, 00010000b ;OR mask to set write data bit .equ spido0, 11101111b ;AND mask to clear write data bit .equ spiclk1, 00100000b ;OR mask to set clock bit .equ spiclk0, 11011111b ;AND mask to clear clock bit .equ spisel1, 01010000b ;OR mask to select SPI device (sets data too) .equ spisel0, 10101111b ;AND mask to deselect SPI device (clears data too) initSPI: mov dptr, #spicon mov a, #spiconv movx @dptr, a mov dptr, #spiport mov r7, #0 clr a movx @dptr,a ; ljmp initSPI1 ;initSPI1: ljmp initSPI2 ;initSPI2: ljmp initSPI3 ;initSPI3: ljmp initSPI4 ;initSPI4: ret SPIdelay: mov r3, #200 SPIdelay1: djnz r3, SPIdelay1 ret writeSPIbyte: ; data to write in R4 ; status returned in acc, 0=accepted mov a, r4 mov r6, a mov a, r7 anl a, #spisel0 movx @dptr, a orl a, #spiclk1 movx @dptr, a anl a, #spiclk0 movx @dptr, a orl a, #spiclk1 movx @dptr, a anl a, #spiclk0 movx @dptr, a orl a, #spisel1 movx @dptr, a orl a, #spiclk1 movx @dptr, a anl a, #spiclk0 movx @dptr, a anl a, #spido0 movx @dptr, a orl a, #spiclk1 movx @dptr, a anl a, #spiclk0 movx @dptr, a orl a, #spiclk1 movx @dptr, a anl a, #spiclk0 mov r7, a movx @dptr, a mov r3, #8 SPIwloop: mov a, r6 rlc a mov r6, a jc SPIout1 mov a, r7 anl a, #spido0 movx @dptr, a ljmp SPIwclockit SPIout1: mov a, r7 orl a, #spido1 movx @dptr, a SPIwclockit: orl a, #spiclk1 movx @dptr, a anl a, #spiclk0 mov r7, a movx @dptr, a djnz r3, SPIwloop movx a, @dptr anl a, #spidi mov r3, a mov a, r7 orl a, #spiclk1 movx @dptr, a anl a, #spiclk0 movx @dptr, a anl a, #spisel0 movx @dptr, a orl a, #spiclk1 movx @dptr, a anl a, #spiclk0 mov r7, a movx @dptr, a mov a, r3 ret writeSPIwait: lcall writeSPIbyte jnz writeSPIwait ret readSPIbyte: ; data returned in R4 ; status returned in acc, 0=valid data mov a, r7 anl a, #spisel0 movx @dptr, a orl a, #spiclk1 movx @dptr, a anl a, #spiclk0 movx @dptr, a orl a, #spiclk1 movx @dptr, a anl a, #spiclk0 movx @dptr, a orl a, #spisel1 movx @dptr, a orl a, #spiclk1 movx @dptr, a anl a, #spiclk0 movx @dptr, a orl a, #spido1 movx @dptr, a orl a, #spiclk1 movx @dptr, a anl a, #spiclk0 movx @dptr, a anl a, #spido0 movx @dptr, a orl a, #spiclk1 movx @dptr, a anl a, #spiclk0 mov r7, a movx @dptr, a mov r4, #0 mov r3, #8 SPIrloop: mov a, r4 rl a mov r4, a movx a, @dptr anl a, #spidi jz SPIrgoon mov a, r4 orl a, #1 mov r4, a SPIrgoon: mov a, r7 orl a, #spiclk1 movx @dptr, a anl a, #spiclk0 mov r7, a movx @dptr, a djnz r3, SPIrloop movx a, @dptr anl a, #spidi mov r3, a mov a, r7 orl a, #spiclk1 movx @dptr, a anl a, #spiclk0 movx @dptr, a anl a, #spisel0 movx @dptr, a orl a, #spiclk1 movx @dptr, a anl a, #spiclk0 mov r7, a movx @dptr, a mov a, r3 ret readSPIwait: lcall readSPIbyte jnz readSPIwait ret USBsync: ; Syncronize with VDRIVE2 device... lcall USBclear mov r4,#'E' lcall writeSPIwait mov r4,#13 lcall writeSPIwait lcall readSPIwait cjne r4,#'E',USBsync lcall readSPIwait cjne r4,#13,USBsync mov r4,#'e' lcall writeSPIwait mov r4,#13 lcall writeSPIwait lcall readSPIwait cjne r4,#'e',USBsync lcall readSPIwait cjne r4,#13,USBsync lcall USBclear ret ; empty buffer... ; note.. only clears remaining immediate response output ; does not clear if more output pending due to internal delay USBclear: lcall initSPI USBclear1: lcall readSPIbyte ljmp USBcw1 USBcw1: ljmp USBcw2 USBcw2: jz USBclear1 mov r6,#100 USBclear2: lcall SPIdelay lcall readSPIbyte jz USBclear1 djnz r6,USBclear2 ret SelectSCSIPH: ;select short command set, binary input/output lcall USBsync ;initSPI and get USB device ready for access mov r4, #'S' lcall writeSPIwait mov r4, #'C' lcall writeSPIwait mov r4, #'S' lcall writeSPIwait mov r4, #13 lcall writeSPIwait lcall USBclear mov r4, #0x91 lcall writeSPIwait mov r4, #0x0D lcall writeSPIwait lcall USBclear ret ;---------------------------------------------------------- ;and the app... BootTheThing: ;check for uninitialized memory clr a mov r1,a ;clear check count mov dptr, #MemCheck movx a,@dptr ;get first byte xrl a,#'W' ;xor it mov tmp,a ;save to temp mov dptr, #MemCheck+3 movx a,@dptr ;get fourth byte cjne a,tmp,BTT1 ;if = temp then inc r1 ; inc check count BTT1: mov a,tmp ;get temp movx @dptr,a ;and put into fourth byte mov dptr, #MemCheck+1 movx a,@dptr ;get second byte xrl a,#'T' ;xor it mov tmp,a ;save to temp mov dptr, #MemCheck+4 movx a,@dptr ;get fifth byte cjne a,tmp,BTT2 ;if = temp then inc r1 ; inc check count BTT2: mov a,tmp ;get temp movx @dptr,a ;and put into fifth byte mov dptr, #MemCheck+2 movx a,@dptr ;etc... xrl a,#'N' mov tmp,a mov dptr, #MemCheck+5 movx a,@dptr cjne a,tmp,BTT3 inc r1 BTT3: mov a,tmp movx @dptr,a ;if R1=3 then already booted, return cjne r1,#3,DoTheBoot ret NoBoot: lcall USBclear ret DoTheBoot: ;boot the HP... clr a ;clear accumulator mov p1, a ;clear port1 signals mov p1_buf, a ;update iram port1 variable lcall SelectSCSIPH mov r4,#0x01 ;DIR command lcall writeSPIwait mov r4,#0x20 lcall writeSPIwait mov r4,#'B' lcall writeSPIwait mov r4,#'O' lcall writeSPIwait mov r4,#'O' lcall writeSPIwait mov r4,#'T' lcall writeSPIwait mov r4,#13 lcall writeSPIwait lcall readSPIwait cjne r4,#13,NoBoot lcall readSPIwait cjne r4,#'B',NoBoot ;do we have a B ? lcall readSPIwait cjne r4,#'O',NoBoot ;do we have an O? lcall readSPIwait cjne r4,#'O',NoBoot ;another O ? lcall readSPIwait cjne r4,#'T',NoBoot ;a T ? lcall readSPIwait cjne r4,#32,NoBoot ;a space ? lcall readSPIwait cjne r4,#0,BootFileGood ;non-zero size? lcall readSPIwait cjne r4,#0,BootFileGood lcall readSPIwait cjne r4,#0,BootFileGood lcall readSPIwait cjne r4,#0,BootFileGood ljmp NoBoot ;it's a directory, don't boot BootFileGood: lcall USBclear mov r4,#0x04 ;RD command lcall writeSPIwait mov r4,#0x20 lcall writeSPIwait mov r4,#'B' lcall writeSPIwait mov r4,#'O' lcall writeSPIwait mov r4,#'O' lcall writeSPIwait mov r4,#'T' lcall writeSPIwait mov r4,#13 lcall writeSPIwait ;all bytes returned will be boot file clr a mov hp_msb,a BootLoop: lcall readSPIwait mov a,r4 mov hp_lsb,a lcall ide_2_hp ljmp BootLoop ;exit with reset switch ;end of autoptr.asm