> RAMCard/s ' Byte-wide RAM Card in &FC00-&FC03 : (, 01-May-2004 v0.10 JGH: Initial version 23 04-May-2004 v0.12 JGH: Can access disk images <: F : : P: Z Workspace contents: d ws+&000 - File buffer n ws+&100 - Pathname x 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 6EQUD CommandTable @EQUD 0:\ SWI chunk number JEQUD 0:\ SWI chunk handler TEQUD 0:\ SWI decoding table ^EQUD 0:\ SWI decoding code h: r .TitleStr |EQUS "BBCRAMCard"  EQUB 0  ALIGN  .HelpStr 0EQUS "BBCRAMCard"+9+ver$+" ("+$,5,11)+")"  EQUB 0  ALIGN : .CommandTable ,EQUS "RAMCard":EQUB 0:ALIGN:EQUD RAMCard 8EQUD &00010001:EQUD RAMCard_Syntax:EQUD RAMCard_Help : 4EQUS "RAMCardLoad":EQUB 0:ALIGN:EQUD RAMCardLoad @EQUD &00010001:EQUD RAMCardLoad_Syntax:EQUD RAMCardLoad_Help : 4EQUS "RAMCardSave":EQUB 0:ALIGN:EQUD RAMCardSave @EQUD &00010001:EQUD RAMCardSave_Syntax:EQUD RAMCardSave_Help &EQUB 0:ALIGN 0: :.RAMCard_Help D6EQUS "Specifies a RAMCard image to access":EQUB 13 N.RAMCard_Syntax X)EQUS "Syntax: RAMCard ":EQUB 13 bEQUB 0:ALIGN l: v.RAMCardLoad_Help ,EQUS "Loads data into a RAMCard":EQUB 13 .RAMCardLoad_Syntax -EQUS "Syntax: RAMCardLoad ":EQUB 13 EQUB 0:ALIGN : .RAMCardSave_Help ,EQUS "Saves data from a RAMCard":EQUB 13 .RAMCardSave_Syntax -EQUS "Syntax: RAMCardSave ":EQUB 13 EQUB 0:ALIGN : : .Initialise stmfd (sp)!,{link}  ldr r0,[r12] orrs r0,r0,#0  4bne Reinitialise ; We already have workspace *5mov r3,#512 ; We want 256+256+some bytes 4Madd r3,r3,#128 ; buffer + filename + port values + ptr + flags, etc >mov r0,#6 Hswi "XOS_Module" R/ldmvsfd (sp)!,{pc} ; Memory claim failed \/str r2,[r12] ; Store in w/s pointer fadd r2,r2,#256 pmov r0,#13 z/strb r0,[r2] ; Clear filename entry add 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 : (mov r3,#8*1024*1024 ; 8Mb ramdisk mov r0,#6 7swi "XOS_Module" ; If claim successful, then... (movvc r3,#8*1024*1024 ; 8Mb ramdisk 5ldrvc r1,[r12] ; Get workspace pointer back -addvc r1,r1,#512 ; Point to variables 2addvc r1,r1,#4 ; Point to memory address -strvc r3,[r1],#4 ; Store RAMCard size $2strvc r2,[r1],#4 ; Store address of memory .: 8.Reinitialise B+cmp r0,r0 ; Clear flags, etc Lldmfd (sp)!,{pc} V: `: j .Finalise tstmfd (sp)!,{link} ~ (stmfd (sp)!,{r0-r5,link} 23ldr r12,[r12] ; Get address of workspace <.add r2,r12,#256 ; r2=>filename buffer F+mov r3,#0 ; Offset into name P.RAMCardLoop Z(ldrb r1,[r0,r3] ; Get character d*strb r1,[r2,r3] ; Store character n+cmp r1,#"!" ; Found char? x&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 6%str r4,[r2],#8 ; Store size @mov r4,#0 J+str r4,[r2] ; Zero and flags Tldmfd (sp)!,{r0-r5,pc} ^: h: r3.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 0-add r2,r12,#512 ; Point to variables :/add r2,r2,#4 ; Point to RAM address D+ldr r3,[r2],#4 ; Set RAMCard size N*ldr r1,[r2] ; Get RAM address Xorrs r1,r1,#0 b,beq RAMCardNoRAM ; No RAM to load to l)add r5,r1,r3 ; r5=end address v+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 *: 4: > .Service H\ In r0=mem[0] R&\ r1=Service_6502IN - &80AD0 \&\ r1=Service_6502OUT - &80AD1 f&\ r1=Service_6502Reset - &80AD2 p\ r2=port z\ 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 ? 8beq Service_6502OUT B%cmp r1,#&2 ; &80AD2 ? Lbeq Service_6502Reset Vldmfd (sp)!,{r1} `mov pc,link ; No j: t: ~.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 ? 20ldmfd (sp)!,{r2} ; Restore port number <1movcs pc,link ; No -> exit unclaimed F) ; Read &FC00-3 P; r0=z80mem[0] Z; r1=corruptable d"; r2=port number - corruptable n; r3=returns Read value x; r4=corruptable ; stack balanced  ; &FC00-2 - b0-b23 address ; &FC03 - 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? 6:bcs ReadByteEnd ; Reading from past end of RAM @/add r2,r12,#256 ; Point to filename J:ldrb r4,[r2] ; Get filename first character T-cmp r4,#"!" ; Filename present? ^,bcs ReadByteFile ; Read from file h-ldr r1,[r2] ; Get RAM address r0orrs 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 ; r3=byte read ; 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 06bne ReadByteBuffer ; Need to read this sector :)ldr r1,[r2] ; Get +flags D3ands r1,r1,#1 ; Has buffer been read? N6beq ReadByteBuffer ; Need to read this sector X.ReadByteGet b0add r0,r12,#512 ; Point to variables l,ldr r0,[r0] ; Get port value v5and r0,r0,#&FF ; Offset into this sector 2ldrb r3,[r12,r0] ; Get byte from buffer ,mov r1,#0 ; Claim the call (mov pc,link ; And return : .ReadByteBuffer Bstmfd (sp)!,{link} ; Save link as we're going to use SWIs /ldr r1,[r2] ; Get +flags again 7ands r1,r1,#2 ; Has buffer been modified? 5beq ReadByteClean ; 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 47bic r4,r4,#&FF ; Lose flags in bottom byte >4mov r0,#1 ; Write with specified H2swi "XOS_GBPB" ; Write updated buffer Rb ReadByteUpdated \.ReadByteClean f*add r1,r12,#256 ; r1=>filename pmov r0,#&40 z,swi "XOS_Find" ; Open for input '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 -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 $+ldmfd (sp)!,{link} ; Get link back .2b ReadByteGet ; Get byte from buffer 8: B: L.Service_6502OUT V0ldmfd (sp)!,{r1} ; Restore call number `-stmfd (sp)!,{r2} ; Save port number j-and r2,r2,#&FF00 ; Lose bottom byte t)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=Write value ; r4=corruptable  ; stack balanced  ; &FC00-2 - b0-b23 address (; &FC04 - byte port 2 <'and r2,r2,#255 ; r2=0/1/2/3 Fcmp r2,#3 P:beq WriteByte ; Write a byte through the port Z7add r2,r2,#512 ; r2 = offset to port values d:strb r3,[r12,r2] ; Store byte to address latches n+mov r1,#0 ; Claim the call xmov 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 h; r3=byte to write r; 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] 04orr r0,r0,#2 ; Flag 'buffer modified' :str r0,[r2] D,mov r1,#0 ; Claim the call N(mov pc,link ; And return X: b.WriteByteBuffer lBstmfd (sp)!,{r5,link} ; Save link as we're going to use SWIs v0mov 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 4mov r0,#&C0 >-swi "XOS_Find" ; Open for update H'mov r1,r0 ; r1=handle R.WriteByteUpdated \(mov r2,r12 ; r2=>buffer f/mov r3,#256 ; 256 bytes to read p0add r0,r12,#512 ; Point to variables z,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 83mov r4,r0 ; Save offset for later B*mov r1,r2 ; r1=>filename Lmov r0,#&C0 ; Vswi "XOS_Find" `'mov r2,r4 ; r2=offset j'mov r1,r0 ; r1=handle t,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