> RAMCard/s ' Byte-wide RAM Card in &FC00-&FC03 : , 01-May-2004 v0.10 JGH: Initial version 3 04-May-2004 v0.12 JGH: Can access disk images :  : : :  Workspace contents:  ws+&000 - File buffer  ws+&100 - Pathname  ws+&200 - Port values  ws+&204 - RAMCard size  ws+&208 ->RAM - ws+&20C - File PTR, byte 0 holds flags: 7 b0=buffer read, b1=buffer needs writing  ws+&210 - flags : Service_6502Base=&80AD0  mcode% &8000:ver$="0.12" sp=13:link=14:pc=15  p=0 1 P%=0:O%=mcode% [OPT p*3+4 EQUD 0:\start EQUD Initialise EQUD Finalise EQUD Service EQUD TitleStr EQUD HelpStr EQUD CommandTable EQUD 0:\ SWI chunk number !EQUD 0:\ SWI chunk handler "EQUD 0:\ SWI decoding table #EQUD 0:\ SWI decoding code $: % .TitleStr &EQUS "BBCRAMCard" ' EQUB 0 ( ALIGN ) .HelpStr *0EQUS "BBCRAMCard"+9+ver$+" ("+$,5,11)+")" + EQUB 0 , ALIGN -: ..CommandTable /,EQUS "RAMCard":EQUB 0:ALIGN:EQUD RAMCard 08EQUD &00010001:EQUD RAMCard_Syntax:EQUD RAMCard_Help 1: 24EQUS "RAMCardLoad":EQUB 0:ALIGN:EQUD RAMCardLoad 3@EQUD &00010001:EQUD RAMCardLoad_Syntax:EQUD RAMCardLoad_Help 4: 54EQUS "RAMCardSave":EQUB 0:ALIGN:EQUD RAMCardSave 6@EQUD &00010001:EQUD RAMCardSave_Syntax:EQUD RAMCardSave_Help 7EQUB 0:ALIGN 8: 9.RAMCard_Help :6EQUS "Specifies a RAMCard image to access":EQUB 13 ;.RAMCard_Syntax <)EQUS "Syntax: RAMCard ":EQUB 13 =EQUB 0:ALIGN >: ?.RAMCardLoad_Help @,EQUS "Loads data into a RAMCard":EQUB 13 A.RAMCardLoad_Syntax B-EQUS "Syntax: RAMCardLoad ":EQUB 13 CEQUB 0:ALIGN D: E.RAMCardSave_Help F,EQUS "Saves data from a RAMCard":EQUB 13 G.RAMCardSave_Syntax H-EQUS "Syntax: RAMCardSave ":EQUB 13 IEQUB 0:ALIGN J: K: L.Initialise Mstmfd (sp)!,{link} Nldr r0,[r12] Oorrs r0,r0,#0 P4bne Reinitialise ; We already have workspace Q5mov r3,#512 ; We want 256+256+some bytes RMadd r3,r3,#128 ; buffer + filename + port values + ptr + flags, etc Smov r0,#6 Tswi "XOS_Module" U/ldmvsfd (sp)!,{pc} ; Memory claim failed V/str r2,[r12] ; Store in w/s pointer Wadd r2,r2,#256 Xmov r0,#13 Y/strb r0,[r2] ; Clear filename entry Zadd r2,r2,#256 [mov r0,#0 \2str r0,[r2],#4 ; &200 - Zero port values ]3str r0,[r2],#4 ; &204 - Zero RAMCard size ^2str r0,[r2],#4 ; &208 - Zero RAM address _-str r0,[r2],#4 ; &20C - Zero file `,str r0,[r2],#4 ; &210 - Zero flags a: b(mov r3,#8*1024*1024 ; 8Mb ramdisk cmov r0,#6 d7swi "XOS_Module" ; If claim successful, then... e(movvc r3,#8*1024*1024 ; 8Mb ramdisk f5ldrvc r1,[r12] ; Get workspace pointer back g-addvc r1,r1,#512 ; Point to variables h2addvc r1,r1,#4 ; Point to memory address i-strvc r3,[r1],#4 ; Store RAMCard size j2strvc r2,[r1],#4 ; Store address of memory k: l.Reinitialise m+cmp r0,r0 ; Clear flags, etc nldmfd (sp)!,{pc} o: p: q .Finalise rstmfd (sp)!,{link} s stmfd (sp)!,{r0-r5,link} 3ldr r12,[r12] ; Get address of workspace .add r2,r12,#256 ; r2=>filename buffer +mov r3,#0 ; Offset into name .RAMCardLoop (ldrb r1,[r0,r3] ; Get character *strb r1,[r2,r3] ; Store character +cmp r1,#"!" ; Found char? &bcc RAMCardNameDone ; Yes, stop 'add r3,r3,#1 ; Update index cmp r3,#255 *bcc RAMCardLoop ; Loop while <256 .RAMCardNameDone mov r1,#13 1strb r1,[r2,r3] ; Store terminating .add r1,r12,#256 ; r0=>filename buffer .ldrb r0,[r1] ; Get first character 'cmp r0,#"!" ; Null filename? +movcc r4,#0 ; Set size to zero +bcc RAMCardNull ; Jump to set size mov r0,#5 0swi "XOS_File" ; Read file information (ands r0,r0,#1 ; Is it a file? :moveq r4,#0 ; Not a file - set length to zero .RAMCardNull -add r2,r12,#512 ; Point to variables 0add r2,r2,#4 ; Point to RAMCard size %str r4,[r2],#8 ; Store size mov r4,#0 +str r4,[r2] ; Zero and flags ldmfd (sp)!,{r0-r5,pc} : : 3.RAMCardLoad ; *RAMCardLoad stmfd (sp)!,{r0-r5,link} 3ldr r12,[r12] ; Get address of workspace -add r2,r12,#512 ; Point to variables /add r2,r2,#8 ; Point to RAM address *ldr r1,[r2] ; Get RAM address orrs r1,r1,#0 ,beq RAMCardNoRAM ; No RAM to load to %mov r3,#0 ; Load to r2 0mov r2,r1 ; r2=address to load to 'mov r1,r0 ; r1=>filename mov r0,#&FF ; r0=Ǖ 3swi "OS_File" ; Load the specified file ldmfd (sp)!,{r0-r5,pc} : : .RAMCardSave stmfd (sp)!,{r0-r5,link} 3ldr r12,[r12] ; Get address of workspace -add r2,r12,#512 ; Point to variables /add r2,r2,#4 ; Point to RAM address +ldr r3,[r2],#4 ; Set RAMCard size *ldr r1,[r2] ; Get RAM address orrs r1,r1,#0 ,beq RAMCardNoRAM ; No RAM to load to )add r5,r1,r3 ; r5=end address +mov r4,r1 ; r4=start address mov r2,#&FD (orr r2,r2,#&0F00 ; r2=&FFD - '' 'mov r1,r0 ; r1=>filename (mov r0,#&0A ; r0=ǚ as type 3swi "OS_File" ; Save the specified file ldmfd (sp)!,{r0-r5,pc} : : .RAMCardNoRAM adr r0,Error_NoRAM swi "OS_GenerateError" ldmfd (sp)!,{r0-r5,pc} .Error_NoRAM equd &80AD0 equs "No RAMCard memory" equb 0 align : : .Service \ In r0=mem[0] &\ r1=Service_6502IN - &80AD0 &\ r1=Service_6502OUT - &80AD1 &\ r1=Service_6502Reset - &80AD2 \ r2=port \ r3=value \ r4=Module base \ Kstmfd (sp)!,{r1} ; Check for Service_6502IN, 6502OUT or 6502Reset and r1,r1,#&FF000 %cmp r1,#&80000 ; &80xxx ? ldmfd (sp)!,{r1} movne pc,link ; No stmfd (sp)!,{r1} and r1,r1,#&FF0 %cmp r1,#&AD0 ; &80ADx ? ldmfd (sp)!,{r1} movne pc,link ; No 2ldr r12,[r12] ; Get workspace address stmfd (sp)!,{r1} and r1,r1,#&F %cmp r1,#&0 ; &80AD0 ? beq Service_6502IN %cmp r1,#&1 ; &80AD1 ? beq Service_6502OUT %cmp r1,#&2 ; &80AD2 ? beq Service_6502Reset ldmfd (sp)!,{r1} mov pc,link ; No : : .Service_6502Reset 0ldmfd (sp)!,{r1} ; Restore call number ;stmfd (sp)!,{link} ;ldmfd (sp)!,{link} (mov pc,link ; Don't claim : : 2.Service_6502IN ; Read from &FC00,1,2,3 0ldmfd (sp)!,{r1} ; Restore call number -stmfd (sp)!,{r2} ; Save port number -and r2,r2,#&FF00 ; Lose bottom byte )cmp r2,#&FC00 ; Port &FCxx ? 0ldmfd (sp)!,{r2} ; Restore port number 1movne pc,link ; No -> exit unclaimed ' ; Read &FCxx -stmfd (sp)!,{r2} ; Save port number *and r2,r2,#&FF ; Lose top byte *cmp r2,#&04 ; Port <&FC04 ? 0ldmfd (sp)!,{r2} ; Restore port number 1movcs pc,link ; No -> exit unclaimed ) ; Read &FC00-3 ; r0=z80mem[0]  ; r1=corruptable  "; r2=port number - corruptable  ; r3=returns Read value  ; r4=corruptable  ; stack balanced  ; &FC00-2 - b0-b23 address ; &FC04 - byte port  (and r2,r2,#3 ; r2=0/1/2/3 cmp r2,#3 :beq ReadByte ; Read a byte through the port 8add r2,r2,#512 ; r2 = offset to port values =ldrb r3,[r12,r2] ; Fetch byte from address latches ,mov r1,#0 ; Claim the call mov pc,link :  .ReadByte 0add r2,r12,#512 ; Point to variables ,ldr r0,[r2],#4 ; Get port value .ldr r1,[r2],#4 ; Get RAMCard size @cmp r0,r1 ; Is port value past end of RAMCard? :bcs ReadByteEnd ; Reading from past end of RAM  /add r2,r12,#256 ; Point to filename !:ldrb r4,[r2] ; Get filename first character "-cmp r4,#"!" ; Filename present? #,bcs ReadByteFile ; Read from file $-ldr r1,[r2] ; Get RAM address %0orrs r1,r1,#0 ; Any RAM available? &/beq ReadByteEnd ; No RAM, just exit '/ldrb r3,[r1,r0] ; Get byte from RAM (.ReadByteEnd ),mov r1,#0 ; Claim the call *mov pc,link +: ,.ReadByteFile -; r0=port value .; r1=RAMCard size /; r2=>filename 0; r3=byte read 1; r4=spare 20add r2,r12,#512 ; Point to variables 3(add r2,r2,#12 ; Point to 41ldr r1,[r2] ; r1=, r0=port value 59bic r1,r1,#&FF ; Remove flags in bottom byte 69bic r0,r0,#&FF ; Remove offset within sector 7cmp r0,r1 86bne ReadByteBuffer ; Need to read this sector 9)ldr r1,[r2] ; Get +flags :3ands r1,r1,#1 ; Has buffer been read? ;6beq ReadByteBuffer ; Need to read this sector <.ReadByteGet =0add r0,r12,#512 ; Point to variables >,ldr r0,[r0] ; Get port value ?5and r0,r0,#&FF ; Offset into this sector @2ldrb r3,[r12,r0] ; Get byte from buffer A,mov r1,#0 ; Claim the call B(mov pc,link ; And return C: D.ReadByteBuffer EBstmfd (sp)!,{link} ; Save link as we're going to use SWIs F/ldr r1,[r2] ; Get +flags again G7ands r1,r1,#2 ; Has buffer been modified? H5beq ReadByteClean ; No need to write buffer I*add r1,r12,#256 ; r1=>filename Jmov r0,#&C0 K-swi "XOS_Find" ; Open for update L'mov r1,r0 ; r1=handle M(mov r2,r12 ; r2=>buffer N0mov r3,#256 ; 256 bytes to write O0add r0,r12,#512 ; Point to variables P(add r0,r0,#12 ; Point to Q#ldr r4,[r0] ; Get R7bic r4,r4,#&FF ; Lose flags in bottom byte S4mov r0,#1 ; Write with specified T2swi "XOS_GBPB" ; Write updated buffer Ub ReadByteUpdated V.ReadByteClean W*add r1,r12,#256 ; r1=>filename Xmov r0,#&40 Y,swi "XOS_Find" ; Open for input Z'mov r1,r0 ; r1=handle [.ReadByteUpdated \(mov r2,r12 ; r2=>buffer ]/mov r3,#256 ; 256 bytes to read ^0add r0,r12,#512 ; Point to variables _,ldr r4,[r0] ; Get port value `7bic r4,r4,#&FF ; Lose offset within sector a-mov r0,#3 ; Use specified b,swi "XOS_GBPB" ; Read to buffer cmov r0,#0 d(swi "XOS_Find" ; Close file e0add r1,r12,#512 ; Point to variables f,ldr r4,[r1],#12 ; Get port value g7bic r4,r4,#&FF ; Lose offset within sector h0orr r4,r4,#1 ; Flag 'buffer read' i3str r4,[r1] ; Store current +flags j+ldmfd (sp)!,{link} ; Get link back k2b ReadByteGet ; Get byte from buffer l: m: n.Service_6502OUT o0ldmfd (sp)!,{r1} ; Restore call number p-stmfd (sp)!,{r2} ; Save port number q-and r2,r2,#&FF00 ; Lose bottom byte r)cmp r2,#&FC00 ; Port &FCxx ? s0ldmfd (sp)!,{r2} ; Restore port number t1movne pc,link ; No -> exit unclaimed u' ; Read &FCxx v-stmfd (sp)!,{r2} ; Save port number w*and r2,r2,#&FF ; Lose top byte x*cmp r2,#&04 ; Port <&FC04 ? y0ldmfd (sp)!,{r2} ; Restore port number z1movcs pc,link ; No -> exit unclaimed {) ; Read &FC00-3 |; r0=z80mem[0] }; r1=corruptable ~"; r2=port number - corruptable ; r3=Write value ; r4=corruptable ; stack balanced  ; &FC00-2 - b0-b23 address ; &FC04 - byte port  'and r2,r2,#255 ; r2=0/1/2/3 cmp r2,#3 :beq WriteByte ; Write a byte through the port 7add r2,r2,#512 ; r2 = offset to port values :strb r3,[r12,r2] ; Store byte to address latches +mov r1,#0 ; Claim the call mov pc,link : .WriteByte 0add r2,r12,#512 ; Point to variables ,ldr r0,[r2],#4 ; Get port value .ldr r1,[r2],#4 ; Get RAMCard size filename ; r3=byte to write ; r4=spare 0add r2,r12,#512 ; Point to variables (add r2,r2,#12 ; Point to 1ldr r1,[r2] ; r1=, r0=port value 9bic r1,r1,#&FF ; Remove flags in bottom byte 9bic r0,r0,#&FF ; Remove offset within sector cmp r0,r1 6bne WriteByteBuffer ; Need to read this sector )ldr r1,[r2] ; Get +flags 3ands r1,r1,#1 ; Has buffer been read? 6beq WriteByteBuffer ; Need to read this sector .WriteByteGet 0add r0,r12,#512 ; Point to variables ,ldr r0,[r0] ; Get port value 5and r0,r0,#&FF ; Offset into this sector 2strb r3,[r12,r0] ; Get byte from buffer 0add r2,r12,#512 ; Point to variables .add r2,r2,#12 ; Point to +flags ldr r0,[r2] 4orr r0,r0,#2 ; Flag 'buffer modified' str r0,[r2] ,mov r1,#0 ; Claim the call (mov pc,link ; And return : .WriteByteBuffer Bstmfd (sp)!,{r5,link} ; Save link as we're going to use SWIs 0mov r5,r3 ; Save byte to write /ldr r1,[r2] ; Get +flags again 7ands r1,r1,#2 ; Has buffer been modified? 5beq WriteByteClean ; No need to write buffer *add r1,r12,#256 ; r1=>filename mov r0,#&C0 -swi "XOS_Find" ; Open for update 'mov r1,r0 ; r1=handle (mov r2,r12 ; r2=>buffer 0mov r3,#256 ; 256 bytes to write 0add r0,r12,#512 ; Point to variables (add r0,r0,#12 ; Point to #ldr r4,[r0] ; Get 7bic r4,r4,#&FF ; Lose flags in bottom byte 4mov r0,#1 ; Write with specified 2swi "XOS_GBPB" ; Write updated buffer b WriteByteUpdated .WriteByteClean *add r1,r12,#256 ; r1=>filename mov r0,#&C0 -swi "XOS_Find" ; Open for update 'mov r1,r0 ; r1=handle .WriteByteUpdated (mov r2,r12 ; r2=>buffer /mov r3,#256 ; 256 bytes to read 0add r0,r12,#512 ; Point to variables ,ldr r4,[r0] ; Get port value 7bic r4,r4,#&FF ; Lose offset within sector -mov r0,#3 ; Use specified ,swi "XOS_GBPB" ; Read to buffer mov r0,#0 (swi "XOS_Find" ; Close file 0add r1,r12,#512 ; Point to variables ,ldr r4,[r1],#12 ; Get port value 7bic r4,r4,#&FF ; Lose offset within sector 0orr r4,r4,#1 ; Flag 'buffer read' 3str r4,[r1] ; Store current +flags :mov r3,r5 ; Get byte to write back to r3 +ldmfd (sp)!,{r5,link} ; Get link back 2b WriteByteGet ; Get byte from buffer ; ; ; ; *REALLY* slow method... Bstmfd (sp)!,{link} ; Save link as we're going to use SWIs 3mov r4,r0 ; Save offset for later *mov r1,r2 ; r1=>filename mov r0,#&C0 ; swi "XOS_Find" 'mov r2,r4 ; r2=offset 'mov r1,r0 ; r1=handle ,mov r0,#1 ; r0='write ptr' #swi "XOS_Args" ; Set +mov r0,r3 ; Byte to write *swi "XOS_BPut" ; Write a byte mov r0,#0 (swi "XOS_Find" ; Close file +ldmfd (sp)!,{link} ; Get link back ,mov r1,#0 ; Claim the call mov pc,link : :  ALIGN ] &"SAVE RAMCard "+~mcode%+" "+~O% *SetType RAMCard Module *Stamp RAMCard