Reading and writing data to disk in FDS

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

Post Reply
HSA Entertainment
Posts: 4
Joined: Sun Sep 29, 2024 6:40 am

Reading and writing data to disk in FDS

Post by HSA Entertainment »

Hi there.
I'm developing my original FDS game with original 3D printed disk. (https://x.com/HSA_Entmt/status/1829779467293900948)
My work is almost completed. But I couldn't implement save high score.

Does anyone know an example of the FDS read/write function?

I'm working with this great example: https://github.com/bbbradsmith/NES-ca65 ... e/tree/fds
And I use these document use as reference: http://cmpslv2.starfree.jp/Famic/Famdis.htm / https://www.nesdev.org/disksystem.txt
Pokun
Posts: 2878
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: Reading and writing data to disk in FDS

Post by Pokun »

How do you reproduce the actual magnetic disk?
User avatar
segaloco
Posts: 348
Joined: Fri Aug 25, 2023 11:56 am
Contact:

Re: Reading and writing data to disk in FDS

Post by segaloco »

You'll want to use the BIOS routine to write a file located at $E239. This and others are documented here https://www.nesdev.org/wiki/FDS_BIOS#BIOS_calls

You'll want to ensure your save file is the last one on the side it is saved to, writing a file resets the "last file" pointer to whatever you write, so subsequent reads by the BIOS won't know about any files past the one you write.
User avatar
TakuikaNinja
Posts: 122
Joined: Mon Jan 09, 2023 6:42 pm
Location: New Zealand
Contact:

Re: Reading and writing data to disk in FDS

Post by TakuikaNinja »

I developed an FDS program which can dump the BIOS data to disk. It's implemented by calling WriteFile ($E239) in a loop to split the data into 1KiB files (to potentially get around write protection measures). Hopefully it gives some idea of how disk I/O is handled within a program: https://github.com/TakuikaNinja/FDS-BIOS-Dumper

P.S. I'd be happy to provide assistance in Japanese via private messages.
Pokun wrote: Sun Sep 29, 2024 1:01 pm How do you reproduce the actual magnetic disk?
We'll have to wait for OP to answer, but I wouldn't be surprised if the magnetic disk was made by trimming one found in a traditional floppy disk. Apparently "Backup Utilisation Techniques Part 10" contained a section on creating DIY disks using a plastic underlay (the kind that's placed underneath notebook pages while writing) and an 8" floppy. (Japanese Source)
HSA Entertainment
Posts: 4
Joined: Sun Sep 29, 2024 6:40 am

Re: Reading and writing data to disk in FDS

Post by HSA Entertainment »

Thanks for your reply.
I tried write new code. (Thank you, TakuikaNinja-San and segaloco-San!)
Full repository is: https://github.com/Hidetyo/FDS-Save-Load-Test/tree/main

This code works to read and write to disk. First, it read disk and displays 4 variables about 3 second. Second, it add 1 to each other and write to disk.

When I use this fds rom to FDS hardware, the motor will works. But variables won't changed.
Also I checked with FDSKey. When data saved, FDSKey displays "Wrong block CRC" message.

Code: Select all

;
; This is main code:
;

.segment "FILE0_DAT"
main:

	jsr as_clear_20191111		; This is my compiler's code

	jsr as_setaspal_20191111		; This is my compiler's code


	NUM1 = $000A
	NUM2 = $000B
	NUM3 = $000C
	NUM4 = $000D

DataLoad:
	jsr $E1B2			; VINTWait
   	 jsr $E1F8           ; Load Data
	.word DiskID
	.word LoadList 
	bne Error
    beq NoData          ; If data cannot find, variables will set 0		

    lda $4031			; If data found, set variables
    sta NUM1
    lda $4031
    sta NUM2
    lda $4031
    sta NUM3
    lda $4031
    sta NUM4
    jmp Disp

Error:	;Error Beep
	lda $4015
	ora #%00000001
	sta $4015
	lda #%10111111
	sta $4000
	lda #%00101011
	sta $4001
	lda #%00000100
	sta $4002
	lda #%11111011
	sta $4003
	jmp Error

DiskID:
	.byte $00 ; manufacturer
	.byte "TST "
	.byte $00 ; game version
	.byte $00 ; side
	.byte $00 ; disk
	.byte $00 ; disk type
	.byte $00 ; unknown

LoadList:
    .byte $05, $FF

NoData:
    lda #$00
    sta NUM1
    sta NUM2
    sta NUM3
    sta NUM4
	jmp Disp

Disp:			;Display variables
	sta $07FF
	lda NUM1
	sta as_point
	lda $07FF

	sta $07FF
	lda #$21
	sta $042E
	lda #$4a
	sta $042F
	jsr as_point_20191111
	lda $07FF

	sta $07FF
	lda NUM2
	sta as_point
	lda $07FF

	sta $07FF
	lda #$21
	sta $042E
	lda #$6a
	sta $042F
	jsr as_point_20191111
	lda $07FF

	sta $07FF
	lda NUM3
	sta as_point
	lda $07FF

	sta $07FF
	lda #$21
	sta $042E
	lda #$8a
	sta $042F
	jsr as_point_20191111
	lda $07FF

	sta $07FF
	lda NUM4
	sta as_point
	lda $07FF

	sta $07FF
	lda #$21
	sta $042E
	lda #$aa
	sta $042F
	jsr as_point_20191111
	lda $07FF

wait_seconds:		;Wait
    lda $2002 
    bpl wait_seconds 
    ldx #0
loop:
    lda $2002
    bpl loop 
    inx
    cpx #180
    bne loop


DataSave:
    inc NUM1
    lda NUM1
    sta $4024
    inc NUM2
    lda NUM2
    sta $4024
    inc NUM3
    lda NUM3
    sta $4024
    inc NUM4
    lda NUM4
    sta $4024

  	jsr $E1B2			;VINTWait
	lda #5				;FILE ID
    jsr $E239           ;LoadData
	.word DiskID
	.word FileHeader 
	bne Error2
    jmp end   

Error2:	;Error Beep
	lda $4015
	ora #%00000001
	sta $4015
	lda #%10111111
	sta $4000
	lda #%00101011
	sta $4001
	lda #%00000100
	sta $4002
	lda #%11111011
	sta $4003
	jmp Error2

end:
    jmp end

;End of my code
Pokun wrote: Sun Sep 29, 2024 1:01 pm How do you reproduce the actual magnetic disk?
My 3D printed disk uses official retail magnetic disk unit. So I took it out from official disk...
Because I don't want to use Nintendo engraved disk.

I apologize about my English skill..... :|
User avatar
segaloco
Posts: 348
Joined: Fri Aug 25, 2023 11:56 am
Contact:

Re: Reading and writing data to disk in FDS

Post by segaloco »

If it helps, the function in question is here labeled as fds_file_write (line 198): https://gitlab.com/segaloco/fdsboot/-/b ... /src/sys.s

If it isn't working for you, you might strip this and the supporting bits out and incorporate the code in your program directly, at least for the time being to more effectively debug it.

Fun fact, several FDS games from Nintendo (and maybe others?) implement an anti-piracy mechanism involving a modified version of disk I/O that has a file count hard-coded into it, ignoring the count in the header. The routine is directly from the boot ROM save that the file count isn't read from disk. The result is you can hide an extra file on the disk that only this modified version of the routine can read. If the data isn't there, the game locks, assuming it was a copy made using stock I/O that wouldn't know anything about the extra file. This doesn't combat every mechanism, but does handle cases where the FDS unit itself is used to extract the disk by exploiting built-in I/O to move files to some sort of external non-volatile memory device.
User avatar
TakuikaNinja
Posts: 122
Joined: Mon Jan 09, 2023 6:42 pm
Location: New Zealand
Contact:

Re: Reading and writing data to disk in FDS

Post by TakuikaNinja »

HSA Entertainment wrote: Mon Sep 30, 2024 11:51 am Thanks for your reply.
I tried write new code. (Thank you, TakuikaNinja-San and segaloco-San!)
Full repository is: https://github.com/Hidetyo/FDS-Save-Load-Test/tree/main

This code works to read and write to disk. First, it read disk and displays 4 variables about 3 second. Second, it add 1 to each other and write to disk.

When I use this fds rom to FDS hardware, the motor will works. But variables won't changed.
Also I checked with FDSKey. When data saved, FDSKey displays "Wrong block CRC" message.

Code: Select all

;
; This is main code:
;

.segment "FILE0_DAT"
main:

	jsr as_clear_20191111		; This is my compiler's code

	jsr as_setaspal_20191111		; This is my compiler's code


	NUM1 = $000A
	NUM2 = $000B
	NUM3 = $000C
	NUM4 = $000D

DataLoad:
	jsr $E1B2			; VINTWait
   	 jsr $E1F8           ; Load Data
	.word DiskID
	.word LoadList 
	bne Error
    beq NoData          ; If data cannot find, variables will set 0		

    lda $4031			; If data found, set variables
    sta NUM1
    lda $4031
    sta NUM2
    lda $4031
    sta NUM3
    lda $4031
    sta NUM4
    jmp Disp

Error:	;Error Beep
	lda $4015
	ora #%00000001
	sta $4015
	lda #%10111111
	sta $4000
	lda #%00101011
	sta $4001
	lda #%00000100
	sta $4002
	lda #%11111011
	sta $4003
	jmp Error

DiskID:
	.byte $00 ; manufacturer
	.byte "TST "
	.byte $00 ; game version
	.byte $00 ; side
	.byte $00 ; disk
	.byte $00 ; disk type
	.byte $00 ; unknown

LoadList:
    .byte $05, $FF

NoData:
    lda #$00
    sta NUM1
    sta NUM2
    sta NUM3
    sta NUM4
	jmp Disp

Disp:			;Display variables
	sta $07FF
	lda NUM1
	sta as_point
	lda $07FF

	sta $07FF
	lda #$21
	sta $042E
	lda #$4a
	sta $042F
	jsr as_point_20191111
	lda $07FF

	sta $07FF
	lda NUM2
	sta as_point
	lda $07FF

	sta $07FF
	lda #$21
	sta $042E
	lda #$6a
	sta $042F
	jsr as_point_20191111
	lda $07FF

	sta $07FF
	lda NUM3
	sta as_point
	lda $07FF

	sta $07FF
	lda #$21
	sta $042E
	lda #$8a
	sta $042F
	jsr as_point_20191111
	lda $07FF

	sta $07FF
	lda NUM4
	sta as_point
	lda $07FF

	sta $07FF
	lda #$21
	sta $042E
	lda #$aa
	sta $042F
	jsr as_point_20191111
	lda $07FF

wait_seconds:		;Wait
    lda $2002 
    bpl wait_seconds 
    ldx #0
loop:
    lda $2002
    bpl loop 
    inx
    cpx #180
    bne loop


DataSave:
    inc NUM1
    lda NUM1
    sta $4024
    inc NUM2
    lda NUM2
    sta $4024
    inc NUM3
    lda NUM3
    sta $4024
    inc NUM4
    lda NUM4
    sta $4024

  	jsr $E1B2			;VINTWait
	lda #5				;FILE ID
    jsr $E239           ;LoadData
	.word DiskID
	.word FileHeader 
	bne Error2
    jmp end   

Error2:	;Error Beep
	lda $4015
	ora #%00000001
	sta $4015
	lda #%10111111
	sta $4000
	lda #%00101011
	sta $4001
	lda #%00000100
	sta $4002
	lda #%11111011
	sta $4003
	jmp Error2

end:
    jmp end

;End of my code
The File Header struct used for saving a file to disk requires you to include data about the file: https://www.nesdev.org/wiki/FDS_BIOS#Fi ... _structure
You seem to have reserved the space for it in zeropage like I did in my project, which you don't actually need to do when the file header block doesn't change between disk accesses. Its contents don't seem to be initialised before it's used by WriteFile, either. I apologise for misleading you with an atypical use case like that. The File Header struct should be placed in your main PRG code instead, with the proper values filled in.

I suppose it doesn't help that the wiki example code only covers disk loading. Maybe I should add an example of disk saving, too. That page really needs to be reorganised... EDIT: I've added the saving example and reorganised the error list.
HSA Entertainment
Posts: 4
Joined: Sun Sep 29, 2024 6:40 am

Re: Reading and writing data to disk in FDS

Post by HSA Entertainment »

TakuikaNinja wrote: Mon Sep 30, 2024 5:12 pm
HSA Entertainment wrote: Mon Sep 30, 2024 11:51 am Thanks for your reply.
I tried write new code. (Thank you, TakuikaNinja-San and segaloco-San!)
Full repository is: https://github.com/Hidetyo/FDS-Save-Load-Test/tree/main

This code works to read and write to disk. First, it read disk and displays 4 variables about 3 second. Second, it add 1 to each other and write to disk.

When I use this fds rom to FDS hardware, the motor will works. But variables won't changed.
Also I checked with FDSKey. When data saved, FDSKey displays "Wrong block CRC" message.

Code: Select all

;
; This is main code:
;

.segment "FILE0_DAT"
main:

	jsr as_clear_20191111		; This is my compiler's code

	jsr as_setaspal_20191111		; This is my compiler's code


	NUM1 = $000A
	NUM2 = $000B
	NUM3 = $000C
	NUM4 = $000D

DataLoad:
	jsr $E1B2			; VINTWait
   	 jsr $E1F8           ; Load Data
	.word DiskID
	.word LoadList 
	bne Error
    beq NoData          ; If data cannot find, variables will set 0		

    lda $4031			; If data found, set variables
    sta NUM1
    lda $4031
    sta NUM2
    lda $4031
    sta NUM3
    lda $4031
    sta NUM4
    jmp Disp

Error:	;Error Beep
	lda $4015
	ora #%00000001
	sta $4015
	lda #%10111111
	sta $4000
	lda #%00101011
	sta $4001
	lda #%00000100
	sta $4002
	lda #%11111011
	sta $4003
	jmp Error

DiskID:
	.byte $00 ; manufacturer
	.byte "TST "
	.byte $00 ; game version
	.byte $00 ; side
	.byte $00 ; disk
	.byte $00 ; disk type
	.byte $00 ; unknown

LoadList:
    .byte $05, $FF

NoData:
    lda #$00
    sta NUM1
    sta NUM2
    sta NUM3
    sta NUM4
	jmp Disp

Disp:			;Display variables
	sta $07FF
	lda NUM1
	sta as_point
	lda $07FF

	sta $07FF
	lda #$21
	sta $042E
	lda #$4a
	sta $042F
	jsr as_point_20191111
	lda $07FF

	sta $07FF
	lda NUM2
	sta as_point
	lda $07FF

	sta $07FF
	lda #$21
	sta $042E
	lda #$6a
	sta $042F
	jsr as_point_20191111
	lda $07FF

	sta $07FF
	lda NUM3
	sta as_point
	lda $07FF

	sta $07FF
	lda #$21
	sta $042E
	lda #$8a
	sta $042F
	jsr as_point_20191111
	lda $07FF

	sta $07FF
	lda NUM4
	sta as_point
	lda $07FF

	sta $07FF
	lda #$21
	sta $042E
	lda #$aa
	sta $042F
	jsr as_point_20191111
	lda $07FF

wait_seconds:		;Wait
    lda $2002 
    bpl wait_seconds 
    ldx #0
loop:
    lda $2002
    bpl loop 
    inx
    cpx #180
    bne loop


DataSave:
    inc NUM1
    lda NUM1
    sta $4024
    inc NUM2
    lda NUM2
    sta $4024
    inc NUM3
    lda NUM3
    sta $4024
    inc NUM4
    lda NUM4
    sta $4024

  	jsr $E1B2			;VINTWait
	lda #5				;FILE ID
    jsr $E239           ;LoadData
	.word DiskID
	.word FileHeader 
	bne Error2
    jmp end   

Error2:	;Error Beep
	lda $4015
	ora #%00000001
	sta $4015
	lda #%10111111
	sta $4000
	lda #%00101011
	sta $4001
	lda #%00000100
	sta $4002
	lda #%11111011
	sta $4003
	jmp Error2

end:
    jmp end

;End of my code
The File Header struct used for saving a file to disk requires you to include data about the file: https://www.nesdev.org/wiki/FDS_BIOS#Fi ... _structure
You seem to have reserved the space for it in zeropage like I did in my project, which you don't actually need to do when the file header block doesn't change between disk accesses. Its contents don't seem to be initialised before it's used by WriteFile, either. I apologise for misleading you with an atypical use case like that. The File Header struct should be placed in your main PRG code instead, with the proper values filled in.

I suppose it doesn't help that the wiki example code only covers disk loading. Maybe I should add an example of disk saving, too. That page really needs to be reorganised... EDIT: I've added the saving example and reorganised the error list.
Thank you! The new example is very nice.
...But I couldn't make correct code. I changed code for only one variable and replace load and write method.
This code will load variable from file No.5 on the disk and save number "123" to the file.

This is new code:

Code: Select all

;
; This is main code:
;

.segment "FILE0_DAT"
main:

	jsr as_clear_20191111		; This is my compiler's code

	jsr as_setaspal_20191111		; This is my compiler's code


	NUM1 = $000A
	NUM2 = $000B
	NUM3 = $000C
	NUM4 = $000D

DataLoad:
	jsr $E1B2			; VINTWait
    jsr $E1F8           ; Load Data
	.word DiskID
	.word LoadList 
	bne Error

    lda $2001			; If data found, set variables
    sta NUM1
    jmp Disp

Error:	;Error Loop
	jmp Error

DiskID:
	.byte $00 ; manufacturer
	.byte "TST "
	.byte $00 ; game version
	.byte $00 ; side
	.byte $00 ; disk
	.byte $00 ; disk type
	.byte $00 ; unknown

LoadList:
    .byte $05, $FF


Disp:			;Display variables
	sta $07FF
	lda NUM1
	sta as_point
	lda $07FF

	sta $07FF
	lda #$21
	sta $042E
	lda #$4a
	sta $042F
	jsr as_point_20191111
	lda $07FF

jmp wait_seconds		;Skip other variables display
	sta $07FF
	lda NUM2
	sta as_point
	lda $07FF

	sta $07FF
	lda #$21
	sta $042E
	lda #$6a
	sta $042F
	jsr as_point_20191111
	lda $07FF

	sta $07FF
	lda NUM3
	sta as_point
	lda $07FF

	sta $07FF
	lda #$21
	sta $042E
	lda #$8a
	sta $042F
	jsr as_point_20191111
	lda $07FF

	sta $07FF
	lda NUM4
	sta as_point
	lda $07FF

	sta $07FF
	lda #$21
	sta $042E
	lda #$aa
	sta $042F
	jsr as_point_20191111
	lda $07FF

wait_seconds:		;Wait
    lda $2002 
    bpl wait_seconds 
    ldx #0
loop:
    lda $2002
    bpl loop 
    inx
    cpx #180
    bne loop


DataSave:
    lda #123
    sta NUM1
	
  	jsr $E1B2			;VINTWait
	lda #$05			;FILE ID
    jsr $E239           ;SaveData
	.word DiskID
	.word FileHeader 
	bne Error2


Error2:	;Error Loop
	jmp Error2
 

end:
    jmp end

FileHeader:       ; In this example, we are saving a game save to disk
   .byte $05    ; file ID code (used by LoadFiles)
   .byte "SAVEDATA" ; file name
   .word $2001   ; load address
   .word $1000    ; file data size
   .byte $00        ; file type (PRG)
   .word $000A     ; source address of file data
   .byte $00        ; source address type (RAM)

;End of my code
I checked binary files.
Before running:

Code: Select all

03 05 05 53 41 56 45 44 41 54 41 01 20 00 10 00 04 90 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
After running;

Code: Select all

03 05 05 53 41 56 45 44 41 54 41 01 20 00 10 00 04 0A 00 FD 0F 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 E1 00 00 00 00 10 C0 40 35 53 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 A0 A4 E7 60 A4 A1 A4 E7 11 E6 83 E2 4E E2 80 9A 62 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 21 AA 05 02 05 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E9 61 A3 62 FA 02 05 04 00 00 0A 08 FD 07 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 E1 00 00 00 00 10 C0 40 35 53 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 A0 A4 E7 60 A4 A1 A4 E7 11 E6 83 E2 4E E2 80 9A 62 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 21 AA 05 02 05 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E9 61 A3 62 FA 02 05 04 00 00
So file was changed. But I cannot find my variable.

My questions are...
1. Should I use lda $*Data adress* when referencing a value from disk? And should the length of the file header be considered? (For example, if a saved data file starts with $2001, I use lda $2001)

2. When writing data to disk, should the “source address of file data” in the File Header indicate the address of the variable? (Within my code, I specify .word $000A to write NUM1.)

3. Can multiple variables be written to disk at the same time?

If it is too difficult for me, I will exclude the save function and release my game with only the current FDS sound support.
Thanks for your support.
Pokun
Posts: 2878
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: Reading and writing data to disk in FDS

Post by Pokun »

TakuikaNinja wrote: Sun Sep 29, 2024 8:07 pm
Pokun wrote: Sun Sep 29, 2024 1:01 pm How do you reproduce the actual magnetic disk?
We'll have to wait for OP to answer, but I wouldn't be surprised if the magnetic disk was made by trimming one found in a traditional floppy disk. Apparently "Backup Utilisation Techniques Part 10" contained a section on creating DIY disks using a plastic underlay (the kind that's placed underneath notebook pages while writing) and an 8" floppy. (Japanese Source)
Oh wow, I didn't know you could make that without some kind of special equipment.

HSA Entertainment wrote: Mon Sep 30, 2024 11:51 am My 3D printed disk uses official retail magnetic disk unit. So I took it out from official disk...
Because I don't want to use Nintendo engraved disk.
Oh I see, that's what I thought but I sort of had hopes that someone were producing new magnetic disks.


TakuikaNinja wrote: Mon Sep 30, 2024 5:12 pm I suppose it doesn't help that the wiki example code only covers disk loading. Maybe I should add an example of disk saving, too. That page really needs to be reorganised... EDIT: I've added the saving example and reorganised the error list.
Thanks for doing that, I long thought the FDS pages was in need for some concrete examples, especially for loading and saving, but I haven't touched FDS coding for years.
User avatar
TakuikaNinja
Posts: 122
Joined: Mon Jan 09, 2023 6:42 pm
Location: New Zealand
Contact:

Re: Reading and writing data to disk in FDS

Post by TakuikaNinja »

HSA Entertainment wrote: Tue Oct 01, 2024 7:02 am So file was changed. But I cannot find my variable.

My questions are...
1. Should I use lda $*Data adress* when referencing a value from disk? And should the length of the file header be considered? (For example, if a saved data file starts with $2001, I use lda $2001)

2. When writing data to disk, should the “source address of file data” in the File Header indicate the address of the variable? (Within my code, I specify .word $000A to write NUM1.)

3. Can multiple variables be written to disk at the same time?

If it is too difficult for me, I will exclude the save function and release my game with only the current FDS sound support.
Thanks for your support.
There's a few problems I've noticed, which also tie into the questions you had:
  • The first 16 bytes of zeropage ($0000~$000F) are often used by the FDS BIOS routines as temporary variables. The variables you're using for the disk saving test ($000A~$000D) may be conflicting with some routines. Try placing the variables in other sections of RAM (e.g. $0300~$07FF, assuming the $0200 page is for OAM DMA), or the PRG-RAM area ($6000~$DFFF).
  • The load address must be the CPU address where the data should be loaded into, and the file data size should match the number of bytes you're trying to save. The address you specified here actually maps to a PPU register (PPUMASK), which is why you aren't getting the values back into RAM, let alone your variables. In this case, just use the same label you assigned to the first variable (same for the file data source address).
  • Questions 1, 2: Your code is inconsistent when it comes to using variable/label names vs absolute address values, which has probably been the main source of confusion here. Modern assemblers let you define and use human-readable labels in place of address values. This applies to memory-mapped registers and FDS BIOS routine calls, too. I often just include pre-made files that assign labels to them, so I don't have to remember addresses every time.
  • Question 3: Yes, the file data size can technically go up to $FFFF (some programs use abnormally large file sizes as a means of copy protection). So practically speaking, an unlimited amount of contiguous bytes can be saved/loaded per file. In fact, it's far more likely that you would run out of room to load the data to/from before you run out of disk space.
You should have a look through your assembler's documentation to understand the features you can use. (I understand that English-only ones can be a struggle if you're not a native speaker/reader) Using assembler features and directives can greatly improve code "cleanliness" and productivity (i.e. you can spend more time designing instead of implementing). CA65/LD65 in particular have some very powerful features.

In the case of save data, you should serialise the game state into a contiguous byte stream (or multiple concatenated ones, if more than one save can be used) and solely use that data for disk saving. Disk loading is the opposite - after loading the serialised data (and presumably after the player selects the save data to be used), de-serialise the data back into the game state before running the main game. I suppose this can be applied to saving in general, whether it uses battery-backed SRAM, passwords, or something else. The only differences are that SRAM is generally more lenient (as it's often mapped to CPU memory and can therefore just be used as RAM), and that passwords are more strict (works better with a bit stream). Perhaps an article on game saving would be a good addition to the wiki? Error detection/correction should probably be covered as well.
HSA Entertainment
Posts: 4
Joined: Sun Sep 29, 2024 6:40 am

Re: Reading and writing data to disk in FDS

Post by HSA Entertainment »

Thank you! Finaly, I could make a code that works correct :D
And I bring it to my game code. It almost works!

Thank you for help me.
I want to make easy exsample for FDS audio and FDS Disk IO in the future.

This is code that works correct for people who has problem same with me:

Code: Select all

main:
	NUM1 = $0300
	NUM2 = $0301
	NUM3 = $0302
	NUM4 = $0303

DataLoad:
	jsr $E1B2			; VINTWait
    jsr $E1F8           ; Load Data
	.word DiskID
	.word LoadList 
	bne Error


    jmp Disp

Error:	;Error Loop
	jmp Error

DiskID:
	.byte $00 ; manufacturer
	.byte "TST "
	.byte $00 ; game version
	.byte $00 ; side
	.byte $00 ; disk
	.byte $00 ; disk type
	.byte $00 ; unknown

LoadList:
    .byte $05, $FF


Disp:			;Display variables
	sta $07FF
	lda NUM1
	sta as_point
	lda $07FF

	sta $07FF
	lda #$21
	sta $042E
	lda #$4a
	sta $042F
	jsr as_point_20191111
	lda $07FF


	sta $07FF
	lda NUM2
	sta as_point
	lda $07FF

	sta $07FF
	lda #$21
	sta $042E
	lda #$6a
	sta $042F
	jsr as_point_20191111
	lda $07FF

	sta $07FF
	lda NUM3
	sta as_point
	lda $07FF

	sta $07FF
	lda #$21
	sta $042E
	lda #$8a
	sta $042F
	jsr as_point_20191111
	lda $07FF

	sta $07FF
	lda NUM4
	sta as_point
	lda $07FF

	sta $07FF
	lda #$21
	sta $042E
	lda #$aa
	sta $042F
	jsr as_point_20191111
	lda $07FF
	jmp wait_seconds

wait_seconds:		;Wait
    lda $2002 
    bpl wait_seconds 
    ldx #0
loop:
    lda $2002
    bpl loop 
    inx
    cpx #180
    bne loop


DataSave:
    lda #114
    sta NUM1
    lda #120
    sta NUM2
    lda #045
    sta NUM3
    lda #076
    sta NUM4
	
  	jsr $E1B2			;VINTWait
	lda #$05			;FILE ID
    jsr $E239           ;SaveData
	.word DiskID
	.word FileHeader 
	bne Error2


Error2:	;Error Loop
	jmp Error2
 

end:
    jmp end

FileHeader:       ; In this example, we are saving a game save to disk
   .byte $05    ; file ID code (used by LoadFiles)
   .byte "SAVEDATA" ; file name
   .word NUM1   ; load address
   .word $0004  ; file data size
   .byte $00    ; file type (PRG)
   .word NUM1   ; source address of file data
   .byte $00    ; source address type (RAM)

;End of code
Post Reply