10
20
30 :
40
50
60
70 :
80 ver$="0.12"
90 ON ERROR REPORT:PRINT ERL:END
100 :
110
120
130
140
150
160
170
180
190
200
210
220
230
240
250
260
270
280
290
300
310
320
330
340
350
360
370
380
390
400
410
420
430
440
450
460
470
480 :
490 Service_6502Base=&80AD0
500 DIM mcode% &8000
510 sp=13:link=14:pc=15
520 FOR p=0 TO 1
530 P%=0:O%=mcode%
540 [OPT p*3+4
550 EQUD 0:\start
560 EQUD Initialise
570 EQUD Finalise
580 EQUD Service
590 EQUD TitleStr
600 EQUD HelpStr
610 EQUD CommandTable
620 EQUD 0:\ SWI chunk number
630 EQUD 0:\ SWI chunk handler
640 EQUD 0:\ SWI decoding table
650 EQUD 0:\ SWI decoding code
660 :
670 .TitleStr
680 EQUS "BBCIDECard"
690 EQUB 0
700 ALIGN
710 .HelpStr
720 EQUS "BBCIDECard"+CHR$9+ver$+" ("+MID$(TIME$,5,11)+")"
730 EQUB 0
740 ALIGN
750 :
760 .CommandTable
770 EQUS "BBCIDE":EQUB 0:ALIGN:EQUD BBCIDE
780 EQUD &00010001:EQUD BBCIDE_Syntax:EQUD BBCIDE_Help
790 :
800 EQUS "BBCIDELoad":EQUB 0:ALIGN:EQUD BBCIDELoad
810 EQUD &00010001:EQUD BBCIDELoad_Syntax:EQUD BBCIDELoad_Help
820 :
830 EQUS "BBCIDESave":EQUB 0:ALIGN:EQUD BBCIDESave
840 EQUD &00010001:EQUD BBCIDESave_Syntax:EQUD BBCIDESave_Help
850 EQUB 0:ALIGN
860 :
870 .BBCIDE_Help
880 EQUS "Specifies a BBCIDE image to access":EQUB 13
890 .BBCIDE_Syntax
900 EQUS "Syntax: BBCIDE <afsp>":EQUB 13
910 EQUB 0:ALIGN
920 :
930 .BBCIDELoad_Help
940 EQUS "Loads data into a BBCIDE":EQUB 13
950 .BBCIDELoad_Syntax
960 EQUS "Syntax: BBCIDELoad <afsp>":EQUB 13
970 EQUB 0:ALIGN
980 :
990 .BBCIDESave_Help
1000 EQUS "Saves data from a BBCIDE":EQUB 13
1010 .BBCIDESave_Syntax
1020 EQUS "Syntax: BBCIDESave <afsp>":EQUB 13
1030 EQUB 0:ALIGN
1040 :
1050 :
1060 .Initialise
1070 stmfd (sp)!,{link}
1080 ldr r0,[r12]
1090 orrs r0,r0,#0
1100 bne Reinitialise ; We already have workspace
1110 mov r3,#256 ; We want 256 bytes
1120 mov r0,#6
1130 swi "XOS_Module"
1140 ldmvsfd (sp)!,{pc} ; Memory claim failed
1150 str r2,[r12] ; Store in w/s pointer
1160 mov r0,#0
1170 mov r1,#256/4 ; Loop for 256/4 words
1180 .InitLoop
1190 str r0,[r2],#4 ; Zero workspace values
1200 subs r1,r1,#1
1210 bne InitLoop
1220 .Reinitialise
1230 ldr r2,[r12] ; Get w/s pointer back
1240 mov r0,#&40
1250 strb r0,[r2,#&47] ; Set DriveReady
1260 mov r0,#0
1270 cmp r0,r0 ; Clear flags, etc
1280 ldmfd (sp)!,{pc}
1290 :
1300 :
1310 .Finalise
1320 stmfd (sp)!,{link}
1330 ldr r3,[r12] ; Get pointer to module's workspace
1340 orrs r3,r3,#0
1350 beq Finalised ; No workspace (shouldn't ever get called this way)
1360 :
1370 ldr r2,[r3,#&24] ; IDE device 0 buffer
1380 orrs r2,r2,#0
1390 movne r0,#7
1400 swine "XOS_Module" ; Release it if used
1410 :
1420 ldr r2,[r3,#&28] ; IDE device 0 pathname
1430 orrs r2,r2,#0
1440 movne r0,#7
1450 swine "XOS_Module" ; Release it if used
1460 :
1470 ldr r2,[r3,#&34] ; IDE device 1 buffer
1480 orrs r2,r2,#0
1490 movne r0,#7
1500 swine "XOS_Module" ; Release it if used
1510 :
1520 ldr r2,[r3,#&38] ; IDE device 1 pathname
1530 orrs r2,r2,#0
1540 movne r0,#7
1550 swine "XOS_Module" ; Release it if used
1560 :
1570 ldr r2,[r12] ; Get pointer to module's workspace
1580 mov r0,#7
1590 swi "XOS_Module" ; Release it
1600 .Finalised
1610 ldmfd (sp)!,{pc}
1620 :
1630 :
1640 .BBCIDE ; *BBCIDE <filename> - should have <device> parameter
1650 stmfd (sp)!,{r0-r5,link}
1660 ; r0=>parameters
1670 ldr r12,[r12] ; Get address of workspace
1680 stmfd (sp)!,{r0} ; Save pointer to parameters
1690 ldr r2,[r12,#&24] ; Get address of file buffer
1700 orrs r2,r2,r2 ; Does buffer exist?
1710 bne BBCIDEBuffer
1720 mov r3,#512
1730 mov r0,#6
1740 swi "XOS_Module" ; Claim space for file buffer
1750 str r2,[r12,#&24] ; Store address of buffer
1760 .BBCIDEBuffer
1770 ldr r2,[r12,#&28] ; Get address of pathname
1780 orrs r2,r2,r2 ; Does pathname space exist?
1790 bne BBCIDEPathname
1800 mov r3,#256
1810 mov r0,#6
1820 swi "XOS_Module" ; Claim space for pathname
1830 str r2,[r12,#&28] ; Store address of pathname
1840 .BBCIDEPathname
1850 ldmfd (sp)!,{r0} ; Get pointer to parameters back
1860 mov r3,#0 ; Offset into name
1870 .BBCIDELoop
1880 ldrb r1,[r0,r3] ; Get character
1890 strb r1,[r2,r3] ; Store character
1900 cmp r1,#ASC"!" ; Found <ctrl> char?
1910 bcc BBCIDENameDone ; Yes, stop
1920 add r3,r3,#1 ; Update index
1930 cmp r3,#255
1940 bcc BBCIDELoop ; Loop while <256
1950 .BBCIDENameDone
1960 mov r1,#13
1970 strb r1,[r2,r3] ; Store terminating <cr>
1980 :
1990 ldrb r0,[r2,#0] ; Get first character
2000 cmp r0,#ASC"!" ; Null filename?
2010 movcc r4,#0 ; Set size to zero
2020 bcc BBCIDENull ; Jump to set size
2030 mov r0,#5 ; r0=ReadInfo
2040 mov r1,r2 ; r1=>filename
2050 swi "XOS_File" ; Read file information
2060 ands r0,r0,#1 ; Is it a file?
2070 moveq r4,#0 ; Not a file - set length to zero
2080 .BBCIDENull
2090 str r4,[r12,#&20] ; Store size
2100 mov r4,#0
2110 str r4,[r12,#&2C] ; Zero PTR and flags
2120 ldmfd (sp)!,{r0-r5,pc}
2130 :
2140 :
2150 .BBCIDELoad ; *BBCIDELoad <filename>
2160 stmfd (sp)!,{r0-r5,link}
2170 ;ldr r12,[r12] ; Get address of workspace
2180 ;add r2,r12,#512 ; Point to variables
2190 ;add r2,r2,#20 ; Point to RAM address
2200 ;ldr r1,[r2] ; Get RAM address
2210 ;orrs r1,r1,#0
2220 ;beq BBCIDENoRAM ; No RAM to load to
2230 ;mov r3,#0 ; Load to r2
2240 ;mov r2,r1 ; r2=address to load to
2250 ;mov r1,r0 ; r1=>filename
2260 ;mov r0,#&FF ; r0=LOAD
2270 ;swi "OS_File" ; Load the specified file
2280 ldmfd (sp)!,{r0-r5,pc}
2290 :
2300 :
2310 .BBCIDESave
2320 stmfd (sp)!,{r0-r5,link}
2330 ;ldr r12,[r12] ; Get address of workspace
2340 ;add r2,r12,#512 ; Point to variables
2350 ;add r2,r2,#16 ; Point to RAM size
2360 ;ldr r3,[r2],#4 ; Set BBCIDE size
2370 ;ldr r1,[r2] ; Get RAM address
2380 ;orrs r1,r1,#0
2390 ;beq BBCIDENoRAM ; No RAM to load to
2400 ;add r5,r1,r3 ; r5=end address
2410 ;mov r4,r1 ; r4=start address
2420 ;mov r2,#&FD
2430 ;orr r2,r2,#&0F00 ; r2=&FFD - 'DATA'
2440 ;mov r1,r0 ; r1=>filename
2450 ;mov r0,#&0A ; r0=SAVE as type
2460 ;swi "OS_File" ; Save the specified file
2470 ldmfd (sp)!,{r0-r5,pc}
2480 :
2490 :
2500 .BBCIDENoRAM
2510 adr r0,Error_NoRAM
2520 swi "OS_GenerateError"
2530 ldmfd (sp)!,{r0-r5,pc}
2540 .Error_NoRAM
2550 equd &80AD0
2560 equs "No BBCIDE memory"
2570 equb 0
2580 align
2590 :
2600 :
2610 .Service
2620 ; In r0=mem[0]
2630 ; r1=Service_6502IN - &80AD0
2640 ; r1=Service_6502OUT - &80AD1
2650 ; r1=Service_6502Reset - &80AD2
2660 ; r2=port
2670 ; r3=value
2680 ; r4=Module base
2690 ;
2700 stmfd (sp)!,{r1} ; Save service call number
2710 and r1,r1,#&FF000 ; Check b12-b19
2720 cmp r1,#&80000 ; &80xxx ?
2730 ldmfd (sp)!,{r1} ; Restore service call number
2740 movne pc,link ; No -> exit unclaimed
2750 :
2760 stmfd (sp)!,{r1}
2770 and r1,r1,#&FF0
2780 cmp r1,#&AD0 ; &80ADx ?
2790 ldmfd (sp)!,{r1}
2800 movne pc,link ; No
2810 :
2820 stmfd (sp)!,{r1}
2830 and r1,r1,#&F
2840 cmp r1,#&3 ; &80AD0..&80AD2 ?
2850 ldmfd (sp)!,{r1}
2860 movcs pc,link ; No
2870 :
2880 stmfd (sp)!,{r2} ; Save port number
2890 and r2,r2,#&FF00 ; Lose bottom byte
2900 cmp r2,#&FC00 ; Port &FCxx ?
2910 ldmfd (sp)!,{r2} ; Restore port number
2920 movne pc,link ; No -> exit unclaimed
2930 :
2940 stmfd (sp)!,{r2} ; Save port number
2950 and r2,r2,#&F0 ; Lose top byte
2960 cmp r2,#&40 ; Port &FC4x ?
2970 ldmfd (sp)!,{r2} ; Restore port number
2980 movne pc,link ; No -> exit unclaimed
2990 :
3000 ldr r12,[r12] ; Get workspace address
3010 stmfd (sp)!,{r1} ; Save service number
3020 and r1,r1,#&F ; Check service number
3030 cmp r1,#&1 ; &80AD0 ?
3040 bcc Service_6502IN
3050 beq Service_6502OUT
3060 ; Fall through to Reset
3070 :
3080 .Service_6502Reset
3090 ldmfd (sp)!,{r1} ; Restore call number, balance stack
3100 ;stmfd (sp)!,{link}
3110 ;ldmfd (sp)!,{link}
3120 mov pc,link ; Don't claim
3130 :
3140 :
3150 .Service_6502IN ; Read from &FC4x
3160 ldmfd (sp)!,{r1} ; Restore call number, balance stack
3170 ; r0=z80mem[0]
3180 ; r1=corruptable
3190 ; r2=port number - corruptable
3200 ; r3=returns Read value
3210 ; r4=corruptable
3220 ; stack balanced
3230 ;
3240 and r2,r2,#&FF ; r2=low byte
3250 cmp r2,#&40
3260 beq ReadIDEByteLow ; Read from &FC40
3270 cmp r2,#&48
3280 beq ReadIDEByteHigh ; Read from &FC48
3290 ldrb r3,[r12,r2] ; Fetch byte from register
3300 mov r1,#0 ; Claim the call
3310 mov pc,link
3320 :
3330 .ReadIDEByteLow
3340 .ReadIDEByteHigh
3350 ldrb r1,[r12,#&46] ; Get IDEHead
3360 ands r1,r1,#&10 ; Device 1 selected?
3370 movne r1,#&00 ; Device not present
3380 bne WriteIDEStatus ; Return with error set
3390 ldr r1,[r12,#&24] ; Get buffer address
3400 orrs r1,r1,r1 ; Does a buffer exist?
3410 beq ReadByteEnd ; No buffer, exit early
3420 :
3430 ldr r1,[r12,#&2C] ; Get current PTR offset
3440 cmp r1,#256 ; Within current buffer?
3450 stmfd (sp)!,{link} ; Save link
3460 blcs UpdateLBA ; Update LBA and PTR if past end of buffer
3470 ldmfd (sp)!,{link} ; Restore link
3480 orrs r1,r1,r1 ; Is PTR zero?
3490 bne ReadByteClean ; No, buffer holds data
3500 :
3510 ldrb r1,[r12,#&46] ; Get head/device/LBA flag
3520 ands r1,r1,#&40 ; Get LBA flag
3530 bne ReadLBA ; Jump to calculate file PTR with LBA
3540 ldrb r1,[r12,#&43] ; Get sector
3550 sub r1,r1,#1
3560 and r0,r1,#63 ; 64 sectors per track
3570 ldrb r1,[r12,#&46] ; Get head
3580 and r1,r1,#3 ; 4 heads per track
3590 orr r0,r0,r1,lsl #6 ; Merge with sector
3600 ldr r1,[r12,#&44] ; Get cylinder
3610 orr r0,r0,r1,lsl #8 ; Merge into head+sector
3620 mov r0,r0,lsl #8 ; Multipy by 256 to get PTR required
3630 b ReadCHS
3640 .ReadLBA
3650 ldr r1,[r12,#&40] ; Get LBA b0-b7 in top byte
3660 and r1,r1,#&FF000000 ; LBA b0-b7 in b24-b31
3670 ldr r0,[r12,#&44] ; LBA b8-b27 in b0-b19
3680 mov r0,r0,lsl #16 ; LBA b8-b23 in b16-b31
3690 orr r0,r0,r1,lsr #16 ; r0=<LBA b8-b23>+<LBA b0-b7>+<&00>
3700 ; r0=file PTR required
3710 .ReadCHS
3720 ; Should check here for double-spacing
3730 ldr r1,[r12,#&20] ; Drive size
3740 cmp r0,r1 ; Reading from past end of drive?
3750 movcs r1,#&41 ; If past end of drive, set error
3760 strcsb r1,[r12,#&47]
3770 movcs r1,#&10 ; Error is SectorNotFound
3780 strcsb r1,[r12,#&41]
3790 bcs ReadByteEnd ; Exit early with error
3800 ldr r1,[r12,#&28] ; Point to pathname
3810 ldrb r2,[r1] ; Get start of pathname
3820 cmp r2,#ASC"!"
3830 movcc r1,#&41 ; No pathname, set error
3840 strccb r1,[r12,#&47]
3850 movcc r1,#&10 ; Error is SectorNotFound
3860 strccb r1,[r12,#&41]
3870 bcc ReadByteEnd ; No pathname, exit early
3880 :
3890 ; r0=file PTR
3900 ; r1=>filename
3910 ; r2=spare
3920 ; r3=byte read
3930 ; r4=spare
3940 stmfd (sp)!,{link} ; Save link as we're going to use SWIs
3950 mov r4,r0 ; PTR to read from
3960 mov r0,#&40
3970 swi "XOS_Find" ; Open for input
3980 mov r3,#256 ; 256 bytes to read
3990 ldr r2,[r12,#&24] ; r2=>buffer
4000 mov r1,r0 ; r1=handle
4010 mov r0,#3 ; Read using specified PTR
4020 swi "XOS_GBPB" ; Read to buffer
4030 mov r0,#0
4040 swi "XOS_Find" ; Close file
4050 ldmfd (sp)!,{link} ; Restore link
4060 :
4070 .ReadByteClean
4080 ldr r1,[r12,#&24] ; Point to buffer
4090 ldr r0,[r12,#&2C] ; Get current PTR offset
4100 ldrb r3,[r1,r0] ; Get byte from buffer
4110 add r0,r0,#1 ; Increment PTR offset
4120 str r0,[r12,#&2C] ; Store updated PTR offset
4130 .ReadByteEnd
4140 mov r1,#0 ; Claim the call
4150 mov pc,link
4160 :
4170 :
4180 .Service_6502OUT ; Write to &FC4x
4190 ldmfd (sp)!,{r1} ; Restore call number, balance stack
4200 ; r0=z80mem[0]
4210 ; r1=corruptable
4220 ; r2=port number - corruptable
4230 ; r3=Write value
4240 ; r4=corruptable
4250 ; stack balanced
4260 ;
4270 and r2,r2,#&FF ; r2=low byte
4280 cmp r2,#&40
4290 beq WriteIDEByteLow ; Write to &FC40
4300 cmp r2,#&47
4310 beq WriteIDECommand ; Write to &FC47
4320 cmp r2,#&48
4330 beq WriteIDEByteHigh ; Write to &FC48
4340 strb r3,[r12,r2] ; Store byte to register
4350 mov r1,#0 ; Claim the call
4360 mov pc,link
4370 :
4380 .WriteIDECommand
4390 strb r3,[r12,#&40] ; Store current command
4400 mov r1,#0
4410 str r1,[r12,#&2C] ; Clear current buffer
4420 mov r1,#&48 ; Set DriveReady+DataReady
4430 .WriteIDEStatus
4440 strb r1,[r12,#&47] ; Set IDEstatus
4450 mov r1,#0
4460 mov pc,link ; Claim the call
4470 ;
4480 .WriteIDEByteLow
4490 .WriteIDEByteHigh
4500 ldrb r1,[r12,#&46] ; Get IDEHead
4510 ands r1,r1,#&10 ; Device 1 selected?
4520 movne r1,#&00 ; Device not present
4530 bne WriteIDEStatus ; Return with error set
4540 ldr r1,[r12,#&24] ; Get buffer address
4550 orrs r1,r1,r1 ; Does a buffer exist?
4560 beq WriteByteEnd ; No buffer, exit early
4570 :
4580 ldr r1,[r12,#&2C] ; Get current PTR offset
4590 cmp r1,#256 ; Is buffer full?
4600 stmfd (sp)!,{link}
4610 blcs UpdateLBA ; Buffer overflowed, move to next sector
4620 ldmfd (sp)!,{link}
4630 :
4640 .WriteByteClean
4650 ldr r1,[r12,#&24] ; Point to buffer
4660 ldr r0,[r12,#&2C] ; Get current PTR offset
4670 strb r3,[r1,r0] ; Put byte into buffer
4680 add r0,r0,#1 ; Increment PTR offset
4690 str r0,[r12,#&2C] ; Store updated PTR offset
4700 cmp r0,#256 ; Is buffer full?
4710 bcc WriteByteEnd ; Buffer not full, exit
4720 :
4730 ldrb r1,[r12,#&46] ; Get head/device/LBA flag
4740 ands r1,r1,#&40 ; Get LBA flag
4750 bne WriteLBA ; Jump to calculate file PTR with LBA
4760 ldrb r1,[r12,#&43] ; Get sector
4770 sub r1,r1,#1
4780 and r0,r1,#63 ; 64 sectors per track
4790 ldrb r1,[r12,#&46] ; Get head
4800 and r1,r1,#3 ; 4 heads per track
4810 orr r0,r0,r1,lsl #6 ; Merge with sector
4820 ldr r1,[r12,#&44] ; Get cylinder
4830 orr r0,r0,r1,lsl #8 ; Merge into head+sector
4840 mov r0,r0,lsl #8 ; Multipy by 256 to get PTR required
4850 b WriteCHS
4860 .WriteLBA
4870 ldr r1,[r12,#&40] ; Get LBA b0-b7 in top byte
4880 and r1,r1,#&FF000000 ; LBA b0-b7 in b24-b31
4890 ldr r0,[r12,#&44] ; LBA b8-b27 in b0-b19
4900 mov r0,r0,lsl #16 ; LBA b8-b23 in b16-b31
4910 orr r0,r0,r1,lsr #16 ; r0=<LBA b8-b23>+<LBA b0-b7>+<&00>
4920 ; r0=file PTR required
4930 .WriteCHS
4940 ldr r1,[r12,#&20] ; Drive size
4950 cmp r0,r1 ; Reading from past end of drive?
4960 movcs r1,#&41 ; If past end of drive, set error
4970 strcsb r1,[r12,#&47]
4980 movcs r1,#&10 ; Error is SectorNotFound
4990 strcsb r1,[r12,#&41]
5000 bcs WriteByteEnd ; If past end of drive, exit early
5010 ldr r1,[r12,#&28] ; Point to pathname
5020 ldrb r2,[r1] ; Get start of pathname
5030 cmp r2,#ASC"!"
5040 movcc r1,#&41 ; No pathname, set error
5050 strccb r1,[r12,#&47]
5060 movcc r1,#&10 ; Error is SectorNotFound
5070 strccb r1,[r12,#&41]
5080 bcc WriteByteEnd ; No pathname, exit early
5090 :
5100 ; r0=file PTR
5110 ; r1=>filename
5120 ; r2=spare
5130 ; r3=byte to write, now spare
5140 ; r4=spare
5150 stmfd (sp)!,{link} ; Save link as we're going to use SWIs
5160 mov r4,r0 ; PTR to write to
5170 mov r0,#&C0
5180 swi "XOS_Find" ; Open for update
5190 mov r3,#256 ; 256 bytes to write
5200 ldr r2,[r12,#&24] ; r2=>buffer
5210 mov r1,r0 ; r1=handle
5220 mov r0,#1 ; Write using specified PTR
5230 swi "XOS_GBPB" ; Write from buffer
5240 mov r0,#0
5250 swi "XOS_Find" ; Close file
5260 ldmfd (sp)!,{link} ; Restore link
5270 :
5280 .WriteByteEnd
5290 mov r1,#0 ; Claim the call
5300 mov pc,link
5310 :
5320 .UpdateLBA ; LBA=LBA+1
5330 ldr r1,[r12,#&40]
5340 sub r1,r1,#&00010000 ; Count=Count-1
5350 adds r1,r1,#&01000000 ; LBAb0-b7=LBAb0-b7+1
5360 str r1,[r12,#&43]
5370 ldrb r1,[r12,#&44]
5380 adc r1,r1,#0 ; LBAb8-b27=LBAb8-b27+cy
5390 str r1,[r12,#&44] ; **WARNING** Overflows into drive
5400 mov r1,#0
5410 str r1,[r12,#&2C] ; Reset PTR offset to zero
5420 mov pc,link
5430 :
5440 ALIGN
5450 ]NEXT
5460 OSCLI"SAVE BBCIDE "+STR$~mcode%+" "+STR$~O%
5470 *SetType BBCIDE Module
5480 *Stamp BBCIDE
5490 END