> IDE/s  IDE interface at &FC40-4F : (= 01-May-2004 v0.10 JGH: Initial version based on RAMCard 2* 24-May-2004 v0.11 JGH: Reading works <3 20-Dec-2004 v0.12 JGH: Geometry 64*4*cylinder F: Pver$="0.12" Z : : d: n Workspace contents: x ws+&000 - RAMCard b0-b7  ws+&001 - RAMCard b0-b7  ws+&002 - RAMCard b0-b7  ws+&003 -> intercepted  ws+&004 - RAMCard size 2 ws+&008 - RAMCard memory address/file buffer ws+&00C - RAMCard pathname - ws+&010 - File PTR, byte 0 holds flags: 7 b0=buffer read, b1=buffer needs writing  ! ws+&020 - IDE device 0 size 7 ws+&024 - IDE device 0 memory address/file buffer % ws+&028 - IDE device 0 pathname ws+&02C - IDE device 0 PTR  ! ws+&030 - IDE device 1 size 7 ws+&034 - IDE device 1 memory address/file buffer "% ws+&038 - IDE device 1 pathname , ws+&03C - IDE device 1 PTR 6 @K ws+&040 -> intercepted -> IDE data even bytes (holds current command) J ws+&041 - IDE Error T ws+&042 - IDE Count ^, ws+&043 - IDE Sector LBA b0-b7 h- ws+&044 - IDE Cylinder Low LBA b8-b15 r. ws+&045 - IDE Cylinder High LBA b16-b23 |. ws+&046 - IDE Head+Drive LBA b24-b27  ws+&047 - IDE Status 1 ws+&048 -> intecepted -> IDE data odd bytes  ws+&049 -  ws+&04A -  ws+&04B -  ws+&04C -  ws+&04D - $ ws+&04E - [Alternative Status]  ws+&04F - [Drive Data] : Service_6502Base=&80AD0  mcode% &8000 sp=13:link=14:pc=15  p=0 1 P%=0:O%=mcode% [OPT p*3+4 &EQUD 0:\start 0EQUD Initialise :EQUD Finalise DEQUD Service NEQUD TitleStr XEQUD HelpStr bEQUD CommandTable lEQUD 0:\ SWI chunk number vEQUD 0:\ SWI chunk handler EQUD 0:\ SWI decoding table EQUD 0:\ SWI decoding code :  .TitleStr EQUS "BBCIDECard"  EQUB 0  ALIGN  .HelpStr 0EQUS "BBCIDECard"+9+ver$+" ("+$,5,11)+")"  EQUB 0  ALIGN : .CommandTable *EQUS "BBCIDE":EQUB 0:ALIGN:EQUD BBCIDE  6EQUD &00010001:EQUD BBCIDE_Syntax:EQUD BBCIDE_Help :  2EQUS "BBCIDELoad":EQUB 0:ALIGN:EQUD BBCIDELoad *>EQUD &00010001:EQUD BBCIDELoad_Syntax:EQUD BBCIDELoad_Help 4: >2EQUS "BBCIDESave":EQUB 0:ALIGN:EQUD BBCIDESave H>EQUD &00010001:EQUD BBCIDESave_Syntax:EQUD BBCIDESave_Help REQUB 0:ALIGN \: f.BBCIDE_Help p5EQUS "Specifies a BBCIDE image to access":EQUB 13 z.BBCIDE_Syntax (EQUS "Syntax: BBCIDE ":EQUB 13 EQUB 0:ALIGN : .BBCIDELoad_Help +EQUS "Loads data into a BBCIDE":EQUB 13 .BBCIDELoad_Syntax ,EQUS "Syntax: BBCIDELoad ":EQUB 13 EQUB 0:ALIGN : .BBCIDESave_Help +EQUS "Saves data from a BBCIDE":EQUB 13 .BBCIDESave_Syntax ,EQUS "Syntax: BBCIDESave ":EQUB 13 EQUB 0:ALIGN : : $.Initialise .stmfd (sp)!,{link} 8ldr r0,[r12] Borrs r0,r0,#0 L4bne Reinitialise ; We already have workspace V,mov r3,#256 ; We want 256 bytes `mov r0,#6 jswi "XOS_Module" t.ldmvsfd (sp)!,{pc} ; Memory claim failed ~/str r2,[r12] ; Store in w/s pointer mov r0,#0 /mov r1,#256/4 ; Loop for 256/4 words  .InitLoop 0str r0,[r2],#4 ; Zero workspace values subs r1,r1,#1 bne InitLoop .Reinitialise /ldr r2,[r12] ; Get w/s pointer back mov r0,#&40 )strb r0,[r2,#&47] ; Set DriveReady mov r0,#0 +cmp r0,r0 ; Clear flags, etc ldmfd (sp)!,{pc}  : :  .Finalise (stmfd (sp)!,{link} 2 - should have parameter rstmfd (sp)!,{r0-r5,link} |, ; r0=>parameters 6ldr r12,[r12] ; Get address of workspace 8stmfd (sp)!,{r0} ; Save pointer to parameters 8ldr r2,[r12,#&24] ; Get address of file buffer 0orrs r2,r2,r2 ; Does buffer exist? bne BBCIDEBuffer mov r3,#512 mov r0,#6 9swi "XOS_Module" ; Claim space for file buffer 5str r2,[r12,#&24] ; Store address of buffer .BBCIDEBuffer 5ldr r2,[r12,#&28] ; Get address of pathname 8orrs r2,r2,r2 ; Does pathname space exist? bne BBCIDEPathname mov r3,#256 mov r0,#6 6swi "XOS_Module" ; Claim space for pathname &7str r2,[r12,#&28] ; Store address of pathname 0.BBCIDEPathname : char? v'bcc BBCIDENameDone ; Yes, stop *add r3,r3,#1 ; Update index cmp r3,#255 -bcc BBCIDELoop ; Loop while <256 .BBCIDENameDone mov r1,#13 4strb r1,[r2,r3] ; Store terminating : 1ldrb r0,[r2,#0] ; Get first character *cmp r0,#"!" ; Null filename? .movcc r4,#0 ; Set size to zero .bcc BBCIDENull ; Jump to set size )mov r0,#5 ; r0=ReadInfo *mov r1,r2 ; r1=>filename 3swi "XOS_File" ; Read file information  +ands r0,r0,#1 ; Is it a file? =moveq r4,#0 ; Not a file - set length to zero  .BBCIDENull *(str r4,[r12,#&20] ; Store size 4mov r4,#0 >.str r4,[r12,#&2C] ; Zero and flags Hldmfd (sp)!,{r0-r5,pc} R: \: f4.BBCIDELoad ; *BBCIDELoad pstmfd (sp)!,{r0-r5,link} z6;ldr r12,[r12] ; Get address of workspace 0;add r2,r12,#512 ; Point to variables 2;add r2,r2,#20 ; Point to RAM address -;ldr r1,[r2] ; Get RAM address ;orrs r1,r1,#0 /;beq BBCIDENoRAM ; No RAM to load to (;mov r3,#0 ; Load to r2 3;mov r2,r1 ; r2=address to load to *;mov r1,r0 ; r1=>filename #;mov r0,#&FF ; r0=Ǖ 5;swi "OS_File" ; Load the specified file ldmfd (sp)!,{r0-r5,pc} : : .BBCIDESave stmfd (sp)!,{r0-r5,link} 6;ldr r12,[r12] ; Get address of workspace $0;add r2,r12,#512 ; Point to variables ./;add r2,r2,#16 ; Point to RAM size 8-;ldr r3,[r2],#4 ; Set BBCIDE size B-;ldr r1,[r2] ; Get RAM address L;orrs r1,r1,#0 V/;beq BBCIDENoRAM ; No RAM to load to `,;add r5,r1,r3 ; r5=end address j.;mov r4,r1 ; r4=start address t;mov r2,#&FD ~+;orr r2,r2,#&0F00 ; r2=&FFD - '' *;mov r1,r0 ; r1=>filename +;mov r0,#&0A ; r0=ǚ as type 5;swi "OS_File" ; Save the specified file ldmfd (sp)!,{r0-r5,pc} : : .BBCIDENoRAM adr r0,Error_NoRAM swi "OS_GenerateError" ldmfd (sp)!,{r0-r5,pc} .Error_NoRAM equd &80AD0 equs "No BBCIDE memory" equb 0  align : (: 2 .Service <; In r0=mem[0] F&; r1=Service_6502IN - &80AD0 P&; r1=Service_6502OUT - &80AD1 Z&; r1=Service_6502Reset - &80AD2 d; r2=port n; r3=value x; r4=Module base ; 6stmfd (sp)!,{r1} ; Save service call number +and r1,r1,#&FF000 ; Check b12-b19 &cmp r1,#&80000 ; &80xxx ? 9ldmfd (sp)!,{r1} ; Restore service call number 2movne pc,link ; No -> exit unclaimed : stmfd (sp)!,{r1} and r1,r1,#&FF0 &cmp r1,#&AD0 ; &80ADx ? ldmfd (sp)!,{r1} movne pc,link ; No : stmfd (sp)!,{r1} and r1,r1,#&F .cmp r1,#&3 ; &80AD0..&80AD2 ? "ldmfd (sp)!,{r1} , movcs pc,link ; No 6: @.stmfd (sp)!,{r2} ; Save port number J.and r2,r2,#&FF00 ; Lose bottom byte T*cmp r2,#&FC00 ; Port &FCxx ? ^1ldmfd (sp)!,{r2} ; Restore port number h2movne pc,link ; No -> exit unclaimed r: |.stmfd (sp)!,{r2} ; Save port number +and r2,r2,#&F0 ; Lose top byte *cmp r2,#&40 ; Port &FC4x ? 1ldmfd (sp)!,{r2} ; Restore port number 2movne pc,link ; No -> exit unclaimed : 3ldr r12,[r12] ; Get workspace address 1stmfd (sp)!,{r1} ; Save service number 2and r1,r1,#&F ; Check service number &cmp r1,#&1 ; &80AD0 ? bcc Service_6502IN beq Service_6502OUT 3 ; Fall through to Reset : .Service_6502Reset @ldmfd (sp)!,{r1} ; Restore call number, balance stack ;stmfd (sp)!,{link} &;ldmfd (sp)!,{link} 0)mov pc,link ; Don't claim :: D: N-.Service_6502IN ; Read from &FC4x X@ldmfd (sp)!,{r1} ; Restore call number, balance stack b; r0=z80mem[0] l; r1=corruptable v"; r2=port number - corruptable ; r3=returns Read value ; r4=corruptable ; stack balanced ; )and r2,r2,#&FF ; r2=low byte cmp r2,#&40 -beq ReadIDEByteLow ; Read from &FC40 cmp r2,#&48 -beq ReadIDEByteHigh ; Read from &FC48 6ldrb r3,[r12,r2] ; Fetch byte from register ,mov r1,#0 ; Claim the call mov pc,link : .ReadIDEByteLow .ReadIDEByteHigh )ldrb r1,[r12,#&46] ; Get IDEHead 0ands r1,r1,#&10 ; Device 1 selected? *0movne r1,#&00 ; Device not present 43bne WriteIDEStatus ; Return with error set >0ldr r1,[r12,#&24] ; Get buffer address H2orrs r1,r1,r1 ; Does a buffer exist? R3beq ReadByteEnd ; No buffer, exit early \: f2ldr r1,[r12,#&2C] ; Get current offset p4cmp r1,#256 ; Within current buffer? z'stmfd (sp)!,{link} ; Save link Dblcs UpdateLBA ; Update LBA and if past end of buffer *ldmfd (sp)!,{link} ; Restore link (orrs r1,r1,r1 ; Is zero? 3bne ReadByteClean ; No, buffer holds data : 6ldrb r1,[r12,#&46] ; Get head/device/LBA flag *ands r1,r1,#&40 ; Get LBA flag ?bne ReadLBA ; Jump to calculate file with LBA (ldrb r1,[r12,#&43] ; Get sector sub r1,r1,#1 2and r0,r1,#63 ; 64 sectors per track &ldrb r1,[r12,#&46] ; Get head /and r1,r1,#3 ; 4 heads per track /orr r0,r0,r1,lsl #6 ; Merge with sector *ldr r1,[r12,#&44] ; Get cylinder 4orr r0,r0,r1,lsl #8 ; Merge into head+sector $>mov r0,r0,lsl #8 ; Multipy by 256 to get required .b ReadCHS 8 .ReadLBA B7ldr r1,[r12,#&40] ; Get LBA b0-b7 in top byte L2and r1,r1,#&FF000000 ; LBA b0-b7 in b24-b31 V2ldr r0,[r12,#&44] ; LBA b8-b27 in b0-b19 `3mov r0,r0,lsl #16 ; LBA b8-b23 in b16-b31 j?orr r0,r0,r1,lsr #16 ; r0=++<&00> t0 ; r0=file required ~ .ReadCHS *; Should check here for double-spacing (ldr r1,[r12,#&20] ; Drive size =cmp r0,r1 ; Reading from past end of drive? =movcs r1,#&41 ; If past end of drive, set error strcsb r1,[r12,#&47] 5movcs r1,#&10 ; Error is SectorNotFound strcsb r1,[r12,#&41] 3bcs ReadByteEnd ; Exit early with error /ldr r1,[r12,#&28] ; Point to pathname 3ldrb r2,[r1] ; Get start of pathname cmp r2,#"!" 4movcc r1,#&41 ; No pathname, set error strccb r1,[r12,#&47]  5movcc r1,#&10 ; Error is SectorNotFound strccb r1,[r12,#&41] 5bcc ReadByteEnd ; No pathname, exit early (: 2; r0=file <; r1=>filename F; r2=spare P; r3=byte read Z; r4=spare dBstmfd (sp)!,{link} ; Save link as we're going to use SWIs n,mov r4,r0 ; to read from xmov r0,#&40 ,swi "XOS_Find" ; Open for input /mov r3,#256 ; 256 bytes to read (ldr r2,[r12,#&24] ; r2=>buffer 'mov r1,r0 ; r1=handle 4mov r0,#3 ; Read using specified ,swi "XOS_GBPB" ; Read to buffer mov r0,#0 (swi "XOS_Find" ; Close file *ldmfd (sp)!,{link} ; Restore link : .ReadByteClean -ldr r1,[r12,#&24] ; Point to buffer 2ldr r0,[r12,#&2C] ; Get current offset 2ldrb r3,[r1,r0] ; Get byte from buffer 0add r0,r0,#1 ; Increment offset 4str r0,[r12,#&2C] ; Store updated offset ".ReadByteEnd ,,mov r1,#0 ; Claim the call 6mov pc,link @: J: T,.Service_6502OUT ; Write to &FC4x ^@ldmfd (sp)!,{r1} ; Restore call number, balance stack h; r0=z80mem[0] r; r1=corruptable |"; r2=port number - corruptable ; r3=Write value ; r4=corruptable ; stack balanced ; )and r2,r2,#&FF ; r2=low byte cmp r2,#&40 ,beq WriteIDEByteLow ; Write to &FC40 cmp r2,#&47 ,beq WriteIDECommand ; Write to &FC47 cmp r2,#&48 ,beq WriteIDEByteHigh ; Write to &FC48 4strb r3,[r12,r2] ; Store byte to register ,mov r1,#0 ; Claim the call mov pc,link : .WriteIDECommand &3strb r3,[r12,#&40] ; Store current command 0mov r1,#0 :2str r1,[r12,#&2C] ; Clear current buffer D6mov r1,#&48 ; Set DriveReady+DataReady N.WriteIDEStatus X+strb r1,[r12,#&47] ; Set IDEstatus bmov r1,#0 l,mov pc,link ; Claim the call v; .WriteIDEByteLow .WriteIDEByteHigh )ldrb r1,[r12,#&46] ; Get IDEHead 0ands r1,r1,#&10 ; Device 1 selected? 0movne r1,#&00 ; Device not present 3bne WriteIDEStatus ; Return with error set 0ldr r1,[r12,#&24] ; Get buffer address 2orrs r1,r1,r1 ; Does a buffer exist? 3beq WriteByteEnd ; No buffer, exit early : 2ldr r1,[r12,#&2C] ; Get current offset -cmp r1,#256 ; Is buffer full? stmfd (sp)!,{link} Dblcs UpdateLBA ; Buffer overflowed, move to next sector  ldmfd (sp)!,{link} :  .WriteByteClean *-ldr r1,[r12,#&24] ; Point to buffer 42ldr r0,[r12,#&2C] ; Get current offset >2strb r3,[r1,r0] ; Put byte into buffer H0add r0,r0,#1 ; Increment offset R4str r0,[r12,#&2C] ; Store updated offset \-cmp r0,#256 ; Is buffer full? f3bcc WriteByteEnd ; Buffer not full, exit p: z6ldrb r1,[r12,#&46] ; Get head/device/LBA flag *ands r1,r1,#&40 ; Get LBA flag ?bne WriteLBA ; Jump to calculate file with LBA (ldrb r1,[r12,#&43] ; Get sector sub r1,r1,#1 2and r0,r1,#63 ; 64 sectors per track &ldrb r1,[r12,#&46] ; Get head /and r1,r1,#3 ; 4 heads per track /orr r0,r0,r1,lsl #6 ; Merge with sector *ldr r1,[r12,#&44] ; Get cylinder 4orr r0,r0,r1,lsl #8 ; Merge into head+sector >mov r0,r0,lsl #8 ; Multipy by 256 to get required b WriteCHS  .WriteLBA 7ldr r1,[r12,#&40] ; Get LBA b0-b7 in top byte 2and r1,r1,#&FF000000 ; LBA b0-b7 in b24-b31 2ldr r0,[r12,#&44] ; LBA b8-b27 in b0-b19 $3mov r0,r0,lsl #16 ; LBA b8-b23 in b16-b31 .?orr r0,r0,r1,lsr #16 ; r0=++<&00> 80 ; r0=file required B .WriteCHS L(ldr r1,[r12,#&20] ; Drive size V=cmp r0,r1 ; Reading from past end of drive? `=movcs r1,#&41 ; If past end of drive, set error jstrcsb r1,[r12,#&47] t5movcs r1,#&10 ; Error is SectorNotFound ~strcsb r1,[r12,#&41] >bcs WriteByteEnd ; If past end of drive, exit early /ldr r1,[r12,#&28] ; Point to pathname 3ldrb r2,[r1] ; Get start of pathname cmp r2,#"!" 4movcc r1,#&41 ; No pathname, set error strccb r1,[r12,#&47] 5movcc r1,#&10 ; Error is SectorNotFound strccb r1,[r12,#&41] 5bcc WriteByteEnd ; No pathname, exit early : ; r0=file ; r1=>filename ; r2=spare  !; r3=byte to write, now spare ; r4=spare Bstmfd (sp)!,{link} ; Save link as we're going to use SWIs (+mov r4,r0 ; to write to 2mov r0,#&C0 <-swi "XOS_Find" ; Open for update F0mov r3,#256 ; 256 bytes to write P(ldr r2,[r12,#&24] ; r2=>buffer Z'mov r1,r0 ; r1=handle d5mov r0,#1 ; Write using specified n/swi "XOS_GBPB" ; Write from buffer xmov r0,#0 (swi "XOS_Find" ; Close file *ldmfd (sp)!,{link} ; Restore link : .WriteByteEnd ,mov r1,#0 ; Claim the call mov pc,link : '.UpdateLBA ; LBA=LBA+1 ldr r1,[r12,#&40] +sub r1,r1,#&00010000 ; Count=Count-1 1adds r1,r1,#&01000000 ; LBAb0-b7=LBAb0-b7+1 str r1,[r12,#&43] ldrb r1,[r12,#&44] 4adc r1,r1,#0 ; LBAb8-b27=LBAb8-b27+cy >str r1,[r12,#&44] ; **WARNING** Overflows into drive mov r1,#0 "4str r1,[r12,#&2C] ; Reset offset to zero ,mov pc,link 6: @ ALIGN J] T%"SAVE BBCIDE "+~mcode%+" "+~O% ^*SetType BBCIDE Module h*Stamp BBCIDE r