10
20
30 :
40
50
60 :
70 ON ERROR REPORT:PRINT ERL:END
80 :
90
100
110
120
130
140
150
160
170
180 :
190 Service_6502Base=&80AD0
200 DIM mcode% &8000:ver$="0.12"
210 sp=13:link=14:pc=15
220 FOR p=0 TO 1
230 P%=0:O%=mcode%
240 [OPT p*3+4
250 EQUD 0:\start
260 EQUD Initialise
270 EQUD Finalise
280 EQUD Service
290 EQUD TitleStr
300 EQUD HelpStr
310 EQUD CommandTable
320 EQUD 0:\ SWI chunk number
330 EQUD 0:\ SWI chunk handler
340 EQUD 0:\ SWI decoding table
350 EQUD 0:\ SWI decoding code
360 :
370 .TitleStr
380 EQUS "BBCRAMCard"
390 EQUB 0
400 ALIGN
410 .HelpStr
420 EQUS "BBCRAMCard"+CHR$9+ver$+" ("+MID$(TIME$,5,11)+")"
430 EQUB 0
440 ALIGN
450 :
460 .CommandTable
470 EQUS "RAMCard":EQUB 0:ALIGN:EQUD RAMCard
480 EQUD &00010001:EQUD RAMCard_Syntax:EQUD RAMCard_Help
490 :
500 EQUS "RAMCardLoad":EQUB 0:ALIGN:EQUD RAMCardLoad
510 EQUD &00010001:EQUD RAMCardLoad_Syntax:EQUD RAMCardLoad_Help
520 :
530 EQUS "RAMCardSave":EQUB 0:ALIGN:EQUD RAMCardSave
540 EQUD &00010001:EQUD RAMCardSave_Syntax:EQUD RAMCardSave_Help
550 EQUB 0:ALIGN
560 :
570 .RAMCard_Help
580 EQUS "Specifies a RAMCard image to access":EQUB 13
590 .RAMCard_Syntax
600 EQUS "Syntax: RAMCard <afsp>":EQUB 13
610 EQUB 0:ALIGN
620 :
630 .RAMCardLoad_Help
640 EQUS "Loads data into a RAMCard":EQUB 13
650 .RAMCardLoad_Syntax
660 EQUS "Syntax: RAMCardLoad <afsp>":EQUB 13
670 EQUB 0:ALIGN
680 :
690 .RAMCardSave_Help
700 EQUS "Saves data from a RAMCard":EQUB 13
710 .RAMCardSave_Syntax
720 EQUS "Syntax: RAMCardSave <afsp>":EQUB 13
730 EQUB 0:ALIGN
740 :
750 :
760 .Initialise
770 stmfd (sp)!,{link}
780 ldr r0,[r12]
790 orrs r0,r0,#0
800 bne Reinitialise ; We already have workspace
810 mov r3,#512 ; We want 256+256+some bytes
820 add r3,r3,#128 ; buffer + filename + port values + ptr + flags, etc
830 mov r0,#6
840 swi "XOS_Module"
850 ldmvsfd (sp)!,{pc} ; Memory claim failed
860 str r2,[r12] ; Store in w/s pointer
870 add r2,r2,#256
880 mov r0,#13
890 strb r0,[r2] ; Clear filename entry
900 add r2,r2,#256
910 mov r0,#0
920 str r0,[r2],#4 ; &200 - Zero port values
930 str r0,[r2],#4 ; &204 - Zero RAMCard size
940 str r0,[r2],#4 ; &208 - Zero RAM address
950 str r0,[r2],#4 ; &20C - Zero file PTR
960 str r0,[r2],#4 ; &210 - Zero flags
970 :
980 mov r3,#8*1024*1024 ; 8Mb ramdisk
990 mov r0,#6
1000 swi "XOS_Module" ; If claim successful, then...
1010 movvc r3,#8*1024*1024 ; 8Mb ramdisk
1020 ldrvc r1,[r12] ; Get workspace pointer back
1030 addvc r1,r1,#512 ; Point to variables
1040 addvc r1,r1,#4 ; Point to memory address
1050 strvc r3,[r1],#4 ; Store RAMCard size
1060 strvc r2,[r1],#4 ; Store address of memory
1070 :
1080 .Reinitialise
1090 cmp r0,r0 ; Clear flags, etc
1100 ldmfd (sp)!,{pc}
1110 :
1120 :
1130 .Finalise
1140 stmfd (sp)!,{link}
1150 ldr r3,[r12] ; Get pointer to module's workspace
1160 orrs r3,r3,#0
1170 beq Finalised ; No workspace (shouldn't ever get called this way)
1180 mov r0,#7
1190 add r3,r3,#512 ; Point to variables
1200 add r3,r3,#8 ; Point to RAM address
1210 ldr r2,[r3]
1220 orrs r2,r2,#0
1230 swine "XOS_Module" ; Release it
1240 ldr r2,[r12] ; Pointer to module's workspace
1250 mov r0,#7
1260 swi "XOS_Module" ; Release it
1270 .Finalised
1280 ldmfd (sp)!,{pc}
1290 :
1300 :
1310 .RAMCard ; *RAMCard <filename>
1320 stmfd (sp)!,{r0-r5,link}
1330 ldr r12,[r12] ; Get address of workspace
1340 add r2,r12,#256 ; r2=>filename buffer
1350 mov r3,#0 ; Offset into name
1360 .RAMCardLoop
1370 ldrb r1,[r0,r3] ; Get character
1380 strb r1,[r2,r3] ; Store character
1390 cmp r1,#ASC"!" ; Found <ctrl> char?
1400 bcc RAMCardNameDone ; Yes, stop
1410 add r3,r3,#1 ; Update index
1420 cmp r3,#255
1430 bcc RAMCardLoop ; Loop while <256
1440 .RAMCardNameDone
1450 mov r1,#13
1460 strb r1,[r2,r3] ; Store terminating <cr>
1470 add r1,r12,#256 ; r0=>filename buffer
1480 ldrb r0,[r1] ; Get first character
1490 cmp r0,#ASC"!" ; Null filename?
1500 movcc r4,#0 ; Set size to zero
1510 bcc RAMCardNull ; Jump to set size
1520 mov r0,#5
1530 swi "XOS_File" ; Read file information
1540 ands r0,r0,#1 ; Is it a file?
1550 moveq r4,#0 ; Not a file - set length to zero
1560 .RAMCardNull
1570 add r2,r12,#512 ; Point to variables
1580 add r2,r2,#4 ; Point to RAMCard size
1590 str r4,[r2],#8 ; Store size
1600 mov r4,#0
1610 str r4,[r2] ; Zero PTR and flags
1620 ldmfd (sp)!,{r0-r5,pc}
1630 :
1640 :
1650 .RAMCardLoad ; *RAMCardLoad <filename>
1660 stmfd (sp)!,{r0-r5,link}
1670 ldr r12,[r12] ; Get address of workspace
1680 add r2,r12,#512 ; Point to variables
1690 add r2,r2,#8 ; Point to RAM address
1700 ldr r1,[r2] ; Get RAM address
1710 orrs r1,r1,#0
1720 beq RAMCardNoRAM ; No RAM to load to
1730 mov r3,#0 ; Load to r2
1740 mov r2,r1 ; r2=address to load to
1750 mov r1,r0 ; r1=>filename
1760 mov r0,#&FF ; r0=LOAD
1770 swi "OS_File" ; Load the specified file
1780 ldmfd (sp)!,{r0-r5,pc}
1790 :
1800 :
1810 .RAMCardSave
1820 stmfd (sp)!,{r0-r5,link}
1830 ldr r12,[r12] ; Get address of workspace
1840 add r2,r12,#512 ; Point to variables
1850 add r2,r2,#4 ; Point to RAM address
1860 ldr r3,[r2],#4 ; Set RAMCard size
1870 ldr r1,[r2] ; Get RAM address
1880 orrs r1,r1,#0
1890 beq RAMCardNoRAM ; No RAM to load to
1900 add r5,r1,r3 ; r5=end address
1910 mov r4,r1 ; r4=start address
1920 mov r2,#&FD
1930 orr r2,r2,#&0F00 ; r2=&FFD - 'DATA'
1940 mov r1,r0 ; r1=>filename
1950 mov r0,#&0A ; r0=SAVE as type
1960 swi "OS_File" ; Save the specified file
1970 ldmfd (sp)!,{r0-r5,pc}
1980 :
1990 :
2000 .RAMCardNoRAM
2010 adr r0,Error_NoRAM
2020 swi "OS_GenerateError"
2030 ldmfd (sp)!,{r0-r5,pc}
2040 .Error_NoRAM
2050 equd &80AD0
2060 equs "No RAMCard memory"
2070 equb 0
2080 align
2090 :
2100 :
2110 .Service
2120 \ In r0=mem[0]
2130 \ r1=Service_6502IN - &80AD0
2140 \ r1=Service_6502OUT - &80AD1
2150 \ r1=Service_6502Reset - &80AD2
2160 \ r2=port
2170 \ r3=value
2180 \ r4=Module base
2190 \
2200 stmfd (sp)!,{r1} ; Check for Service_6502IN, 6502OUT or 6502Reset
2210 and r1,r1,#&FF000
2220 cmp r1,#&80000 ; &80xxx ?
2230 ldmfd (sp)!,{r1}
2240 movne pc,link ; No
2250 stmfd (sp)!,{r1}
2260 and r1,r1,#&FF0
2270 cmp r1,#&AD0 ; &80ADx ?
2280 ldmfd (sp)!,{r1}
2290 movne pc,link ; No
2300 ldr r12,[r12] ; Get workspace address
2310 stmfd (sp)!,{r1}
2320 and r1,r1,#&F
2330 cmp r1,#&0 ; &80AD0 ?
2340 beq Service_6502IN
2350 cmp r1,#&1 ; &80AD1 ?
2360 beq Service_6502OUT
2370 cmp r1,#&2 ; &80AD2 ?
2380 beq Service_6502Reset
2390 ldmfd (sp)!,{r1}
2400 mov pc,link ; No
2410 :
2420 :
2430 .Service_6502Reset
2440 ldmfd (sp)!,{r1} ; Restore call number
2450 ;stmfd (sp)!,{link}
2460 ;ldmfd (sp)!,{link}
2470 mov pc,link ; Don't claim
2480 :
2490 :
2500 .Service_6502IN ; Read from &FC00,1,2,3
2510 ldmfd (sp)!,{r1} ; Restore call number
2520 stmfd (sp)!,{r2} ; Save port number
2530 and r2,r2,#&FF00 ; Lose bottom byte
2540 cmp r2,#&FC00 ; Port &FCxx ?
2550 ldmfd (sp)!,{r2} ; Restore port number
2560 movne pc,link ; No -> exit unclaimed
2570 ; Read &FCxx
2580 stmfd (sp)!,{r2} ; Save port number
2590 and r2,r2,#&FF ; Lose top byte
2600 cmp r2,#&04 ; Port <&FC04 ?
2610 ldmfd (sp)!,{r2} ; Restore port number
2620 movcs pc,link ; No -> exit unclaimed
2630 ; Read &FC00-3
2640 ; r0=z80mem[0]
2650 ; r1=corruptable
2660 ; r2=port number - corruptable
2670 ; r3=returns Read value
2680 ; r4=corruptable
2690 ; stack balanced
2700
2710 ; &FC00-2 - b0-b23 address
2720 ; &FC03 - byte port
2730
2740 and r2,r2,#3 ; r2=0/1/2/3
2750 cmp r2,#3
2760 beq ReadByte ; Read a byte through the port
2770 add r2,r2,#512 ; r2 = offset to port values
2780 ldrb r3,[r12,r2] ; Fetch byte from address latches
2790 mov r1,#0 ; Claim the call
2800 mov pc,link
2810 :
2820 .ReadByte
2830 add r2,r12,#512 ; Point to variables
2840 ldr r0,[r2],#4 ; Get port value
2850 ldr r1,[r2],#4 ; Get RAMCard size
2860 cmp r0,r1 ; Is port value past end of RAMCard?
2870 bcs ReadByteEnd ; Reading from past end of RAM
2880 add r2,r12,#256 ; Point to filename
2890 ldrb r4,[r2] ; Get filename first character
2900 cmp r4,#ASC"!" ; Filename present?
2910 bcs ReadByteFile ; Read from file
2920 ldr r1,[r2] ; Get RAM address
2930 orrs r1,r1,#0 ; Any RAM available?
2940 beq ReadByteEnd ; No RAM, just exit
2950 ldrb r3,[r1,r0] ; Get byte from RAM
2960 .ReadByteEnd
2970 mov r1,#0 ; Claim the call
2980 mov pc,link
2990 :
3000 .ReadByteFile
3010 ; r0=port value
3020 ; r1=RAMCard size
3030 ; r2=>filename
3040 ; r3=byte read
3050 ; r4=spare
3060 add r2,r12,#512 ; Point to variables
3070 add r2,r2,#12 ; Point to PTR
3080 ldr r1,[r2] ; r1=PTR, r0=port value
3090 bic r1,r1,#&FF ; Remove flags in bottom byte
3100 bic r0,r0,#&FF ; Remove offset within sector
3110 cmp r0,r1
3120 bne ReadByteBuffer ; Need to read this sector
3130 ldr r1,[r2] ; Get PTR+flags
3140 ands r1,r1,#1 ; Has buffer been read?
3150 beq ReadByteBuffer ; Need to read this sector
3160 .ReadByteGet
3170 add r0,r12,#512 ; Point to variables
3180 ldr r0,[r0] ; Get port value
3190 and r0,r0,#&FF ; Offset into this sector
3200 ldrb r3,[r12,r0] ; Get byte from buffer
3210 mov r1,#0 ; Claim the call
3220 mov pc,link ; And return
3230 :
3240 .ReadByteBuffer
3250 stmfd (sp)!,{link} ; Save link as we're going to use SWIs
3260 ldr r1,[r2] ; Get PTR+flags again
3270 ands r1,r1,#2 ; Has buffer been modified?
3280 beq ReadByteClean ; No need to write buffer
3290 add r1,r12,#256 ; r1=>filename
3300 mov r0,#&C0
3310 swi "XOS_Find" ; Open for update
3320 mov r1,r0 ; r1=handle
3330 mov r2,r12 ; r2=>buffer
3340 mov r3,#256 ; 256 bytes to write
3350 add r0,r12,#512 ; Point to variables
3360 add r0,r0,#12 ; Point to PTR
3370 ldr r4,[r0] ; Get PTR
3380 bic r4,r4,#&FF ; Lose flags in bottom byte
3390 mov r0,#1 ; Write with specified PTR
3400 swi "XOS_GBPB" ; Write updated buffer
3410 b ReadByteUpdated
3420 .ReadByteClean
3430 add r1,r12,#256 ; r1=>filename
3440 mov r0,#&40
3450 swi "XOS_Find" ; Open for input
3460 mov r1,r0 ; r1=handle
3470 .ReadByteUpdated
3480 mov r2,r12 ; r2=>buffer
3490 mov r3,#256 ; 256 bytes to read
3500 add r0,r12,#512 ; Point to variables
3510 ldr r4,[r0] ; Get port value
3520 bic r4,r4,#&FF ; Lose offset within sector
3530 mov r0,#3 ; Use specified PTR
3540 swi "XOS_GBPB" ; Read to buffer
3550 mov r0,#0
3560 swi "XOS_Find" ; Close file
3570 add r1,r12,#512 ; Point to variables
3580 ldr r4,[r1],#12 ; Get port value
3590 bic r4,r4,#&FF ; Lose offset within sector
3600 orr r4,r4,#1 ; Flag 'buffer read'
3610 str r4,[r1] ; Store current PTR+flags
3620 ldmfd (sp)!,{link} ; Get link back
3630 b ReadByteGet ; Get byte from buffer
3640 :
3650 :
3660 .Service_6502OUT
3670 ldmfd (sp)!,{r1} ; Restore call number
3680 stmfd (sp)!,{r2} ; Save port number
3690 and r2,r2,#&FF00 ; Lose bottom byte
3700 cmp r2,#&FC00 ; Port &FCxx ?
3710 ldmfd (sp)!,{r2} ; Restore port number
3720 movne pc,link ; No -> exit unclaimed
3730 ; Read &FCxx
3740 stmfd (sp)!,{r2} ; Save port number
3750 and r2,r2,#&FF ; Lose top byte
3760 cmp r2,#&04 ; Port <&FC04 ?
3770 ldmfd (sp)!,{r2} ; Restore port number
3780 movcs pc,link ; No -> exit unclaimed
3790 ; Read &FC00-3
3800 ; r0=z80mem[0]
3810 ; r1=corruptable
3820 ; r2=port number - corruptable
3830 ; r3=Write value
3840 ; r4=corruptable
3850 ; stack balanced
3860
3870 ; &FC00-2 - b0-b23 address
3880 ; &FC04 - byte port
3890
3900 and r2,r2,#255 ; r2=0/1/2/3
3910 cmp r2,#3
3920 beq WriteByte ; Write a byte through the port
3930 add r2,r2,#512 ; r2 = offset to port values
3940 strb r3,[r12,r2] ; Store byte to address latches
3950 mov r1,#0 ; Claim the call
3960 mov pc,link
3970 :
3980 .WriteByte
3990 add r2,r12,#512 ; Point to variables
4000 ldr r0,[r2],#4 ; Get port value
4010 ldr r1,[r2],#4 ; Get RAMCard size
4020 cmp r0,r1 ; Is port value past end of RAM?
4030 bcs WriteByteEnd ; Writing past end of RAM
4040 add r2,r12,#256 ; Point to filename
4050 ldrb r4,[r2] ; Get filename first character
4060 cmp r4,#ASC"!" ; Filename present?
4070 bcs WriteByteFile ; Write to file
4080 ldr r1,[r2] ; Get RAM address
4090 orrs r1,r1,#0 ; Any RAM available?
4100 beq WriteByteEnd ; No RAM, exit
4110 strb r3,[r1,r0] ; Put byte to RAM
4120 .WriteByteEnd
4130 mov r1,#0 ; Claim the call
4140 mov pc,link
4150 :
4160 .WriteByteFile
4170 ; r0=port value
4180 ; r1=RAMCard size
4190 ; r2=>filename
4200 ; r3=byte to write
4210 ; r4=spare
4220 add r2,r12,#512 ; Point to variables
4230 add r2,r2,#12 ; Point to PTR
4240 ldr r1,[r2] ; r1=PTR, r0=port value
4250 bic r1,r1,#&FF ; Remove flags in bottom byte
4260 bic r0,r0,#&FF ; Remove offset within sector
4270 cmp r0,r1
4280 bne WriteByteBuffer ; Need to read this sector
4290 ldr r1,[r2] ; Get PTR+flags
4300 ands r1,r1,#1 ; Has buffer been read?
4310 beq WriteByteBuffer ; Need to read this sector
4320 .WriteByteGet
4330 add r0,r12,#512 ; Point to variables
4340 ldr r0,[r0] ; Get port value
4350 and r0,r0,#&FF ; Offset into this sector
4360 strb r3,[r12,r0] ; Get byte from buffer
4370 add r2,r12,#512 ; Point to variables
4380 add r2,r2,#12 ; Point to PTR+flags
4390 ldr r0,[r2]
4400 orr r0,r0,#2 ; Flag 'buffer modified'
4410 str r0,[r2]
4420 mov r1,#0 ; Claim the call
4430 mov pc,link ; And return
4440 :
4450 .WriteByteBuffer
4460 stmfd (sp)!,{r5,link} ; Save link as we're going to use SWIs
4470 mov r5,r3 ; Save byte to write
4480 ldr r1,[r2] ; Get PTR+flags again
4490 ands r1,r1,#2 ; Has buffer been modified?
4500 beq WriteByteClean ; No need to write buffer
4510 add r1,r12,#256 ; r1=>filename
4520 mov r0,#&C0
4530 swi "XOS_Find" ; Open for update
4540 mov r1,r0 ; r1=handle
4550 mov r2,r12 ; r2=>buffer
4560 mov r3,#256 ; 256 bytes to write
4570 add r0,r12,#512 ; Point to variables
4580 add r0,r0,#12 ; Point to PTR
4590 ldr r4,[r0] ; Get PTR
4600 bic r4,r4,#&FF ; Lose flags in bottom byte
4610 mov r0,#1 ; Write with specified PTR
4620 swi "XOS_GBPB" ; Write updated buffer
4630 b WriteByteUpdated
4640 .WriteByteClean
4650 add r1,r12,#256 ; r1=>filename
4660 mov r0,#&C0
4670 swi "XOS_Find" ; Open for update
4680 mov r1,r0 ; r1=handle
4690 .WriteByteUpdated
4700 mov r2,r12 ; r2=>buffer
4710 mov r3,#256 ; 256 bytes to read
4720 add r0,r12,#512 ; Point to variables
4730 ldr r4,[r0] ; Get port value
4740 bic r4,r4,#&FF ; Lose offset within sector
4750 mov r0,#3 ; Use specified PTR
4760 swi "XOS_GBPB" ; Read to buffer
4770 mov r0,#0
4780 swi "XOS_Find" ; Close file
4790 add r1,r12,#512 ; Point to variables
4800 ldr r4,[r1],#12 ; Get port value
4810 bic r4,r4,#&FF ; Lose offset within sector
4820 orr r4,r4,#1 ; Flag 'buffer read'
4830 str r4,[r1] ; Store current PTR+flags
4840 mov r3,r5 ; Get byte to write back to r3
4850 ldmfd (sp)!,{r5,link} ; Get link back
4860 b WriteByteGet ; Get byte from buffer
4870 ;
4880 ;
4890 ;
4900 ; *REALLY* slow method...
4910 stmfd (sp)!,{link} ; Save link as we're going to use SWIs
4920 mov r4,r0 ; Save offset for later
4930 mov r1,r2 ; r1=>filename
4940 mov r0,#&C0 ; OPENUP
4950 swi "XOS_Find"
4960 mov r2,r4 ; r2=offset
4970 mov r1,r0 ; r1=handle
4980 mov r0,#1 ; r0='write ptr'
4990 swi "XOS_Args" ; Set PTR
5000 mov r0,r3 ; Byte to write
5010 swi "XOS_BPut" ; Write a byte
5020 mov r0,#0
5030 swi "XOS_Find" ; Close file
5040 ldmfd (sp)!,{link} ; Get link back
5050 mov r1,#0 ; Claim the call
5060 mov pc,link
5070 :
5080 :
5090 ALIGN
5100 ]NEXT
5110 OSCLI"SAVE RAMCard "+STR$~mcode%+" "+STR$~O%
5120 *SetType RAMCard Module
5130 *Stamp RAMCard
5140 END