Write binary data to TRD from ASM
Re: Write binary data to TRD from ASM
Another thing I'm stuck with - at the conceptual level.
I'm trying to save two files to disk. One is only 1 byte (the selected language, 1 sector), the other is 960 bytes (the high score table), 4 sectors.
I can write files with call #0B (Save <C> file). This only works if I save a new file, though. If I save an existing file, I get error 0 returned, suggesting it worked, but the contents don't change.
I can also delete the file with call #12. Then saving it works, but creates a new file at the end of the catalog, and leaves the sectors of the original file marked as deleted.
I would prefer to save the same file repeatedly, with the same filename, in the same sector. I'd rather not MOVE the disk programmatically to reclaim the deleted sectors.
There exist the sequential and random access files that can be used with OPEN #/PRINT #/INPUT#/CLOSE #. Will they do the job? Can they be only called the "official" API way, by placing tokenized Basic commands in memory? It looks like these have the disadvantage of not being able to be used on <C> files, as they have their own special <#> type.
There also exist PEEK/POKE "filename"Buffer_address, Sector_numbers commands. It looks like these can be used to read and write <C> files. Do they also have to be used with the "official" API?
There are calls to read (#05) and write(#06) individual sectors, but I can't see how to read the track and sector numbers from the catalogue. I know what my initial sectors are, as I built the disk, but I would corrupt the disk if I assumed that, as someone might do their own disk operations that moved the file.
What do you think the best and easiest way to do this is?
I also discovered that writing to a read-only disk displays the nice Retry, Ignore, Abort message, which clears my screen. I worked round this by saving and restoring the screen before and after all my disk commands. I read in Russian about a service screen - is this what's happening here? Has my screen already been saved, and I could restore it by calling TR-DOS?
I'm trying to save two files to disk. One is only 1 byte (the selected language, 1 sector), the other is 960 bytes (the high score table), 4 sectors.
I can write files with call #0B (Save <C> file). This only works if I save a new file, though. If I save an existing file, I get error 0 returned, suggesting it worked, but the contents don't change.
I can also delete the file with call #12. Then saving it works, but creates a new file at the end of the catalog, and leaves the sectors of the original file marked as deleted.
I would prefer to save the same file repeatedly, with the same filename, in the same sector. I'd rather not MOVE the disk programmatically to reclaim the deleted sectors.
There exist the sequential and random access files that can be used with OPEN #/PRINT #/INPUT#/CLOSE #. Will they do the job? Can they be only called the "official" API way, by placing tokenized Basic commands in memory? It looks like these have the disadvantage of not being able to be used on <C> files, as they have their own special <#> type.
There also exist PEEK/POKE "filename"Buffer_address, Sector_numbers commands. It looks like these can be used to read and write <C> files. Do they also have to be used with the "official" API?
There are calls to read (#05) and write(#06) individual sectors, but I can't see how to read the track and sector numbers from the catalogue. I know what my initial sectors are, as I built the disk, but I would corrupt the disk if I assumed that, as someone might do their own disk operations that moved the file.
What do you think the best and easiest way to do this is?
I also discovered that writing to a read-only disk displays the nice Retry, Ignore, Abort message, which clears my screen. I worked round this by saving and restoring the screen before and after all my disk commands. I read in Russian about a service screen - is this what's happening here? Has my screen already been saved, and I could restore it by calling TR-DOS?
Robin Verhagen-Guest
SevenFFF / Threetwosevensixseven / colonel32
NXtel • NXTP • ESP Update • ESP Reset • CSpect Plugins
SevenFFF / Threetwosevensixseven / colonel32
NXtel • NXTP • ESP Update • ESP Reset • CSpect Plugins
Re: Write binary data to TRD from ASM
The whole 'leaving gaps' issue is normal in a sense, and is expected of programs that operate on the file level. Notice that, as long as the file you're working with is the last file on the disk, no gap would be left if it is deleted and subsequently saved back.
On the other hand, doing a MOVE within a game program is certainly an overkill and not what most people would expect. It's a bit like if a PC game tried to defragment the HDD on its own!
Random access and other unusual formats are best avoided. I doubt most people have any idea what those are (myself included), and I don't remember a single program that used those on a regular basis for its functionality.
(Why not just keep a single 961 byte file? Loading 4 sectors and 1 sector takes virtually the same time, and this is more efficient in terms of using the disk space.)
You can use a combination of #0A and #08 to read the track/sector information, and then read/save the data with #05 and #06. Sort of like this:
Another option is to do the #0A/#08 thing once in the beginning, store the file locations/lengths in memory, and then just use #05/#06 as needed. This would help to reduce unnecessary drive head movements to track 0 and back (is faster). Also, #05/#06 have the advantage of not requiring the extra buffer in order to work.
It's definitely not doing anything that convenient.
The correct way to go about this is to intercept the Retry/Abort/Ignore message. The following code comes from my unfinished #3D13 driver so again, pretty much untested, but I believe it should be something along these lines.
On the other hand, doing a MOVE within a game program is certainly an overkill and not what most people would expect. It's a bit like if a PC game tried to defragment the HDD on its own!
Random access and other unusual formats are best avoided. I doubt most people have any idea what those are (myself included), and I don't remember a single program that used those on a regular basis for its functionality.
(Why not just keep a single 961 byte file? Loading 4 sectors and 1 sector takes virtually the same time, and this is more efficient in terms of using the disk space.)
Seven.FFF wrote: ↑Sat Dec 16, 2017 10:05 pm There are calls to read (#05) and write(#06) individual sectors, but I can't see how to read the track and sector numbers from the catalogue. I know what my initial sectors are, as I built the disk, but I would corrupt the disk if I assumed that, as someone might do their own disk operations that moved the file.
You can use a combination of #0A and #08 to read the track/sector information, and then read/save the data with #05 and #06. Sort of like this:
Code: Select all
Overwrite
ld hl,FileDescriptor
ld c,#13 ;copy the file descriptor to TR-DOS system variables
call #3D13
ld a,9 ;find a file with matching 9 first bytes in the descriptor (filename and type)
ld (#5D06),a ;uses the extra buffer, as do file level operations
ld c,#0A
call #3D13
ld a,c
inc c ;C will contain #FF if the file with this name wasn't found
jr z,NoFile
ld c,#08 ;#3D13 C=#08: loads a file descriptor specified in A at #5CDD
call #3D13
ld hl,SaveAddress ;or LD HL,(#5CE6) to assume the same saving address as in the file descriptor
ld de,(#5CEB) ;file descriptor: track and sector
ld a,(#5CEA) ;file descriptor: length, sectors
ld b,a
ld c,#06 ;#3D13 C=#06: save sectors
call #3D13
ret
Seven.FFF wrote: ↑Sat Dec 16, 2017 10:05 pm I also discovered that writing to a read-only disk displays the nice Retry, Ignore, Abort message, which clears my screen. I worked round this by saving and restoring the screen before and after all my disk commands. I read in Russian about a service screen - is this what's happening here? Has my screen already been saved, and I could restore it by calling TR-DOS?
It's definitely not doing anything that convenient.
The correct way to go about this is to intercept the Retry/Abort/Ignore message. The following code comes from my unfinished #3D13 driver so again, pretty much untested, but I believe it should be something along these lines.
Code: Select all
OneTimeInit
ld a,#C3 ;#5CC2: is used by TR-DOS to call the BASIC 48 ROM routines, typically contains a RET
ld (#5CC2),a ;is also executed upon error during a #3D13 call (see #0201)
ld hl,ErrorHandler ;here, it is set to 'JP ErrorHandler'
ld (#5CC3),hl
ret
DOS
ld,(iy+0),#FF ;set #5C3A to 'no error', this is checked before exiting in #0201 but isn't reset by the DOS
push hl
ld (#5C3D),sp ;#5C3D: ERRSP
ld hl,0 ;zero out the two byte error code at #5D0F
ld (#5D0F),hl
pop hl
call #3D13
ret z ;Z: OK, NZ: ERROR
ld a,c ;C = error code
cp 20
jr z,Break ;20: break
sub 6
jr z,NoDisc ;6: no disc
dec a
jr z,DiscError ;7: disc error (abort)
jr UnhandledError
;intercept the Retry/Abort/Ignore message
ErrorHandler
ex (sp),hl ;will eventually return if entered upon NO DISC or ABORT, with the error code in C
push af
ld a,h
cp #0D ;the RIA situation is indicated by #0D6B on the stack (both 5.03 and 5.01)
jr z,.ria
pop af ;otherwise, we continue
ex (sp),hl ;LIST, CAT, FORMAT and the like display additional messages, not handled here
ret
.ria
ld hl,12 ;10+2
add hl,sp
ld sp,hl
call RIAMessage ;our custom RIA procedure here, A should return an "R"/"I"/"A" ASCII code
ld hl,#3F7E ;5.01 uses #3F74
push hl ;return the user's response to TR-DOS
jp #3D2F
Inactive account
Re: Write binary data to TRD from ASM
I've just hit this one too. My Uno is loaded with 5.04T (UK), and doesn't even get past the first DOS command in the basic loader. I think this might be the version where the entry points have changed. I need to write a good detection routine.keith56 wrote: ↑Sat Dec 09, 2017 12:32 am it seems my problem was not the code, or trdtool, but something with my emulator, I was using TR-DOS 5.04 (UK) and it was somehow failing to even save a bas file to a newly formatted disk from it's own interface (It was renaming the disk??!!)
Well, I've moved to 6.04 (Russian) and the example works perfectly, so I don't know if I had a corrupt rom, or something messed up on my emulator, but all is good now! - out of interest, what is the best rom to use for testing (compatibility wise?)
Somewhere I saw a handy list of differences between several TR-DOS versions, but I can't find it now.
Thanks! Your suggestion works nicely (on 5.03)!Hikaru wrote: ↑Sun Dec 17, 2017 8:06 am The whole 'leaving gaps' issue is normal in a sense, and is expected of programs that operate on the file level. Notice that, as long as the file you're working with is the last file on the disk, no gap would be left if it is deleted and subsequently saved back.
On the other hand, doing a MOVE within a game program is certainly an overkill and not what most people would expect. It's a bit like if a PC game tried to defragment the HDD on its own!
Random access and other unusual formats are best avoided. I doubt most people have any idea what those are (myself included), and I don't remember a single program that used those on a regular basis for its functionality.
(Why not just keep a single 961 byte file? Loading 4 sectors and 1 sector takes virtually the same time, and this is more efficient in terms of using the disk space.)
This is great, thanks. I haven't got this working yet (lack of time). But I will try to do soHikaru wrote: ↑Sun Dec 17, 2017 8:06 am Another option is to do the #0A/#08 thing once in the beginning, store the file locations/lengths in memory, and then just use #05/#06 as needed. This would help to reduce unnecessary drive head movements to track 0 and back (is faster). Also, #05/#06 have the advantage of not requiring the extra buffer in order to work.
Ah, brilliant, thanks! I tried to do this before but couldn't figure it out. Much better way of handling it. I want the language selection to always write back to the disk when you start, but silently fail if it is write protected or something else happens. Resetting the high score table should only happen when you pick that option, and should fail verbosely. That why I originally had them as separate files. I can still do it the way I want having them share a file, it's just a little more complicated.
Last edited by Seven.FFF on Fri Dec 22, 2017 9:57 pm, edited 1 time in total.
Robin Verhagen-Guest
SevenFFF / Threetwosevensixseven / colonel32
NXtel • NXTP • ESP Update • ESP Reset • CSpect Plugins
SevenFFF / Threetwosevensixseven / colonel32
NXtel • NXTP • ESP Update • ESP Reset • CSpect Plugins
Re: Write binary data to TRD from ASM
Aaargh no, Everything looks the same between 5.03 and 5.04T, unless i missed something.
Robin Verhagen-Guest
SevenFFF / Threetwosevensixseven / colonel32
NXtel • NXTP • ESP Update • ESP Reset • CSpect Plugins
SevenFFF / Threetwosevensixseven / colonel32
NXtel • NXTP • ESP Update • ESP Reset • CSpect Plugins
Re: Write binary data to TRD from ASM
Actually I'm completely wrong. Everything is working on 5.04T in SpecEmu. On the Uno, everything works except one of my #3D13 load commands, when the progress bar is about 85%.
I will need to hook up a debugger to see what is happening.
I will need to hook up a debugger to see what is happening.
Robin Verhagen-Guest
SevenFFF / Threetwosevensixseven / colonel32
NXtel • NXTP • ESP Update • ESP Reset • CSpect Plugins
SevenFFF / Threetwosevensixseven / colonel32
NXtel • NXTP • ESP Update • ESP Reset • CSpect Plugins
Re: Write binary data to TRD from ASM
Good to know. I've had a similar experience recently trying to figure out the (low-level) +3DOS stuff. Those multi-byte OUTs/INs, madness.
Inactive account
- Alessandro
- Dynamite Dan
- Posts: 1910
- Joined: Wed Nov 15, 2017 11:10 am
- Location: Messina, Italy
- Contact:
Re: Write binary data to TRD from ASM
Hi, I suppose that's because you typed "CODE" in the string as four separate characters instead of the single character 175.Seven.FFF wrote: ↑Wed Dec 13, 2017 7:39 pm I had been trying to get this one working too. This is the "official" API that passes tokenized basic commands to TR-Dos. I ran into issues with my tokenization - the stuff in my reference REM statements were being tokenised as "C", "O", "D", "E" etc and it was causing confusion with some other problems I was having at the same time. It clearly works in my basic loader though, so I could revisit this later. But I don't really need to.
Tokenization of BASIC commands is actually more useful to me since it allows me, with a simple trick, to modify the code of the TR-DOS file management program, so that it can be compatible with the Brazilian clones of the Beta Disk interface, i.e. Arcade AR-20, IDS-91, CBI-95, which point of access for the commands is 15363 instead of 15619. This was pointed to my attention by Flávio Massao Matsumoto, and I have employed it in many of my games.
Code: Select all
LET d = 15363 + 256 * PEEK (15363<>195)
If for instance the call routine is located at 25000:
Code: Select all
25000 034 093 092 LD (CHADD),HL
25003 205 003 061 CALL 15619
25006 042 181 097 LD HL,(TEMP)
25009 034 093 092 LD (CHADD),HL
25012 201 RET
25013 DEFS 2
Code: Select all
IF d = 15619 THEN POKE 25005,61
IF d = 15363 THEN POKE 25005,60
Re: Write binary data to TRD from ASM
That’s very useful, thanks Alessandro!
Robin Verhagen-Guest
SevenFFF / Threetwosevensixseven / colonel32
NXtel • NXTP • ESP Update • ESP Reset • CSpect Plugins
SevenFFF / Threetwosevensixseven / colonel32
NXtel • NXTP • ESP Update • ESP Reset • CSpect Plugins
- Alessandro
- Dynamite Dan
- Posts: 1910
- Joined: Wed Nov 15, 2017 11:10 am
- Location: Messina, Italy
- Contact:
Re: Write binary data to TRD from ASM
You are welcome
Of course HL should point to the BASIC command of the block you wish to load. Another example, related to my post above (loading routine at 25000):
Notice that the CODE function is stored as character 175.
Of course HL should point to the BASIC command of the block you wish to load. Another example, related to my post above (loading routine at 25000):
Code: Select all
LD HL, CHADD
LD (TEMP),HL
LD HL,BLOCK
CALL 25000
RET
BLOCK:
DEFB 234 ; REM
DEFM ":"
DEFB 239 ; LOAD
DEFB 34 ; "
DEFM "FILENAME"
DEFB 34 ; "
DEFB 175 ; CODE
DEFB 13 ; [ENTER]
- Alessandro
- Dynamite Dan
- Posts: 1910
- Joined: Wed Nov 15, 2017 11:10 am
- Location: Messina, Italy
- Contact:
Re: Write binary data to TRD from ASM
Update. This comes from the forthcoming new version of the Al's Double Bill compilation.
Here is the "boot" program for the disk (any BASIC program named "boot" will be executed when RUN is entered at the TR-DOS prompt):
Line 20 checks if PEEK 15363 = 195; in this case, d = 15363 and a non-standard Beta Disk interface is connected.
And here is the code for the first MC block loaded from disk. First, it checks the type of Beta Disk interface - standard or not -, then it "recognizes" whether it is running on a 48K or not. Finally, it loads the main selection program accordingly.
The first trick was suggested to me by Einar Saukas, the second by Flávio Matsumoto.
Here is the "boot" program for the disk (any BASIC program named "boot" will be executed when RUN is entered at the TR-DOS prompt):
Code: Select all
10 BORDER NOT PI: PAPER NOT PI: INK NOT PI: BRIGHT SGN PI: CLEAR VAL "24499"
20 LET d=VAL "15363"+VAL "256"*(PEEK 15363<>195)
30 RANDOMIZE USR d : REM : LOAD "ADB" CODE
40 RANDOMIZE USR VAL "24500"
And here is the code for the first MC block loaded from disk. First, it checks the type of Beta Disk interface - standard or not -, then it "recognizes" whether it is running on a 48K or not. Finally, it loads the main selection program accordingly.
The first trick was suggested to me by Einar Saukas, the second by Flávio Matsumoto.
Code: Select all
ORG 24500
KEY_VAL EQU 24587
CHADD EQU 23645
CALL CLEANER
LD HL, ADB_SCR
LD DE, 16384
CALL dzx7
LD B,150
CALL DELAY
LD A,(15363)
CP 195
JR NZ, MEMORY ; if PEEK 15363 <> 195 then a standard Beta Disk is connected
LD A,60
LD (KEY_VAL),A ; ...otherwise it is a clone and the location is modified
MEMORY:
LD A,(2899)
CP 165
JR NZ,ZX128
ZX48:
LD HL,(CHADD)
LD (TEMP),HL
LD HL,ADB48
CALL TRDOS
JP 32770
ZX128:
LD HL,(CHADD)
LD (TEMP),HL
LD HL,ADB128
CALL TRDOS
JP 32770
DELAY:
HALT
DJNZ DELAY
RET
CLEANER:
LD A,64 ; (64 for BRIGHT 1)
LD (23693),A ; PAPER 0, INK 0, BRIGHT 1
LD (23624),A ; the last two rows have INK and PAPER set to 0
CALL 3503 ; CLS
RET
TRDOS:
LD (CHADD),HL
CALL 15619 ; recalls the TR-DOS loading routine (the last byte here is KEY_VAL)
LD HL,(TEMP) ; reloads CHADD's original value in HL
LD (CHADD),HL ; restores CHADD's original value
RET
TEMP: DEFS 2 ; CHADD's original value is stored here
ADB48:
DEFB 234 ; REM
DEFM ":"
DEFB 239 ; LOAD
DEFB 34 ; "
DEFM "ADB-48"
DEFB 34 ; "
DEFB 175 ; CODE
DEFB 13 ; [ENTER]
ADB128:
DEFB 234 ; REM
DEFM ":"
DEFB 239 ; LOAD
DEFB 34 ; "
DEFM "ADB-128"
DEFB 34 ; "
DEFB 175 ; CODE
DEFB 13 ; [ENTER]
INCLUDE "dzx7_agileRCS.asm" ; Einar Saukas's RCS-ZX7 integrated decompressor
ADB_SCR: INCBIN "ADB-ZX7.bin" ; compressed loading screen