+3 how to detect if a file exist ?

2»

Comments

  • edited May 2010
    That piece I did yesterday was just typed up in Notepad and pasted into Spin's assembler. On a real 48k Spectrum I use OCP's Editor/Assembler and Test Tool, but I'd expect them to be incompatible with the 128k+3. As you might have gathered, machine coding on the 128k Speccies is even trickier than usual because of the memory bank paging.
  • edited May 2010
    I cross-develop under Linux, using zmakebas to generate BASIC loaders, z80asm to assemble machine code and taptools to combine the results into a tapefile.

    In the case of this program, where I had to generate a BASIC program that poked machine code into a REM statement, I wrote a custom program in C to generate the listing from the output of z80asm. Then I used zmakebas to convert the listing into a tapefile that I could load and test. (Exercise for the interested reader: spot the minor mistake I made in this process).
  • edited May 2010
    na_th_an wrote: »
    Correct me if I'm wrong, but wouldn't such a low CLEAR leave virtually no space for anything else than the BASIC MC loader? Why not put such code just below the UDG area, and leave the whole RAM for the BASIC program?

    Code that calls +3DOS has to be below 0C000h. And the stack has to be below 0BFE0h. That's why I put my code (and stack) in a REM statement -- it's very unlikely that the program will start that high in memory.
  • edited May 2010
    spodula, can you show the assembler code of this last one you posted ? I am trying to understand it.

    thx in advance.
  • edited May 2010
    You can look at the disassembly in Spin. Just load & run that BASIC demo from #30, select Tools->Debugger, right-click in the disassembly pane, select Go To ..., type in the start address of the m/code and you can scroll through the disassembly from there.
  • edited May 2010
    ok, thx. It is had to start with this kind of language :P

    But exist a way to copy and paste the basic code on teh zx spin ?, because the asm editor allow us to copy and paste.
  • edited May 2010
    arfgh wrote: »
    But exist a way to copy and paste the basic code on teh zx spin ?, because the asm editor allow us to copy and paste.

    If there is, it's very well hidden ...

    If I want to load a BASIC program from a text file I use Martijn's BAS2TAP which is in the Utilities section here. There's BASin as well, of course, but I've never used that - and Taper - Convert which comes with the Z80 emulator - probably others that I don't know about.
  • edited May 2010
    arfgh wrote: »
    spodula, can you show the assembler code of this last one you posted ? I am trying to understand it.

    thx in advance.

    Again, this is battlebunny's code, not mine. I'm just doing some hand-disassembly using the manual. Just like old times :p
    Note, while doing this i have spotted some errors with my code. Ah well.
    Basically, i didnt change the address of the filename in the code. Likewise, the stack and its storage should be set above RAMTOP.
    ;Initially, we need to setup an environment to call the DOS routines. 
    ;This consists of paging in ROM 2 to $0000-$3FFF and RAM 7 to $C000-$FFFF
    48896    DI               ;While doing paging, Interrupts should be disabled 
                              ;so we dont page out something important. 
                              ;(Not required in this code because its in the 
                              ;middle 32K, but its a good habit to get into anyway)
    48897    LD (36864),SP    ;Store the BASIC stack pointer. Note, this again 
                              ;is probably a bit supurfluous as RAMTOP is in 
                              ;the middle 32K
    ;When messing with memory pages from a program 
    ;that expects to return to BASIC, or a program that 
    ;expects to use the ROM routines, we need to keep the contents of 
    ;the BANKM system variable up to date with the last value written to 7FFD
    48901    LD BC, 32765     ;Load BC with the address of the paging port. 7FFD
    48904    LD A,(23388)     ;Get the contents of BANKM (last value written to 7FFD)
    48907    RES 4,A          ;Set bit for ROM LSB to 0 (switching ROM3 to ROM2)
    48909    OR %00000111     ;Merge in 7 (Selecting RAM page 7 to $C000)
    48911    LD (23387),A     ;set last value outputted
    48914    OUT (C),A        ;and actually output it. 
    48916    LD SP, 40959     ;Set a stack above ramtop, but below $C000
    48919    EI               ;and re-enable interrupts. 
    
    ;This bit of the code is responsible for calling the ROM routine. 
    ;This attempts to open the named file and returns 1 if it succeeds, or 0 
    ;if fails. (See the +3 Manual for more information on DOS_OPEN
    48920    LD B,3           ;Choose DOS channel 3
    48922    LD C,5           ;Access mode shared-read 
    48924    LD D,0           ;Create action = 0. (Ie, Dont, just Error if file doesnt exist)
    48926    LD E,1           ;Open action = 1. (Open the file)
    48928    LD HL,28659      ;Address of the filename (Note, this is where my error is!)
    48931    CALL 262         ;call DOS_OPEN ($106)
    
    48934    LD BC,0          ;Default return value = 0
    48937    JR NC,+3         ;if carry=false, skip over the next statement.
    48939    LD BC,1          ;If however, that isnt the case, return value = 1
    48941    PUSH BC          ;store return value
    
    48942    LD BC, 32765     ;Load BC with the address of the paging port. 7FFD
    48945    LD A,(23387)     ;Get the contents of BANKM
    48948    SET 4,A          ;Set bit for ROM LSB to 1 (switching ROM2 to ROM3)
    48950    AND %11111000    ;Reset the last three bits. (for Ram page 0)
    48952    LD (23387),A     ;set last value outputted
    48955    OUT (C),A        ;and actually output it. 
    48957    POP BC           ;Set back our return value from the stack.
    48958    LD SP,(36864)    ;And restore the original stack. 
    48961    RET              ;and were done. 
    
    ;For details of the following block, see above.
    48962    DI
    48963    LD (36864),SP
    48967    LD BC, 32765
    48970    LD A,(23387)
    48973    RES 4,A
    48975    OR %00000111
    48977    LD (23387),A
    48980    OUT (C),A
    48982    LD SP, 40959
    48985    EI
    
    ;This simply calls DOS_CLOSE to ensure we dont leave the file
    ;hanging. 
    48986    LD B,3     ;DOS channel #3
    48988    CALL 265 ;call DOS_CLOSE
    
    ;For details of the following block, see above.
    48991    LD BC, 32765
    48994    LD A,(23387)
    48996    SET 4,A
    48998    AND %11111000
    49000    LD (23387),A
    49003    OUT (C),A
    49005    LD SP,(36864)
    49008    RET
    
  • edited June 2010
    As proposed in #21, here's a version of the file check routine which uses DEF FN to define the file name as a parameter, so it doesn't need to be POKEd anywhere and the code becomes relocatable. Done with some help from chapter 9 of Toni Baker's "Mastering Machine Code" book.

    The function definition is:
    DEF FN o(f$)=USR 49050
    where f$ is the file name + CHR$ 255.
            ;set up DOS environment
            di             ; 49050 243
            ld bc, 32765   ; 49051 1   253 127
            ld a, (23388)  ; 49054 58  92  91
            res 4, a       ; 49057 203 167
            or 7           ; 49059 246 7
            ld (23388), a  ; 49061 50  92  91
            out (c), a     ; 49064 237 121
    
            ;check if file exists
            ld hl, (23563) ; 49066 42  11  92  ;DEFADD holds start of FN o(f$) arg
            ld de, 4       ; 49069 17  4   0
            add hl, de     ; 49072 25          ;HL=location of f$ address
            ld e, (hl)     ; 49073 94          ;E =lo byte  of f$ address
            inc hl         ; 49074 35
            ld d, (hl)     ; 49075 86          ;D =hi byte  of f$ address
            ex de, hl      ; 49076 235         ;HL=f$ address
            ld bc, 773     ; 49077 1   5   3   ;B =file ID 3, C =access mode 5
            ld de, 1       ; 49080 17  1   0   ;D =create action 0, E =open action 1
            call 262       ; 49083 205 6   1   ;call DOS-OPEN
            ld bc, 0       ; 49086 1   0   0   ;BC=flag error
            jr nc, l_bfc6  ; 49089 48  3       ;jump if error (Carry unset)
            ld bc, 1       ; 49091 1   1   0   ;BC=flag OK
    l_bfc6: push bc        ; 49094 197         ;save status
            ld b, 3        ; 49095 6   3       ;B =file ID 3
            call 265       ; 49097 205 9   1   ;call DOS-CLOSE
    
            ;restore BASIC environment
            ld bc, 32765   ; 49100 1   253 127
            ld a, (23388)  ; 49103 58  92  91
            set 4, a       ; 49106 203 231
            and 248        ; 49108 230 248
            ld (23388), a  ; 49110 50  92  91
            out (c), a     ; 49113 237 121
            ei             ; 49115 251
            pop bc         ; 49116 193         ;restore status
            ret            ; 49117 201         ;return status
    
  • edited June 2010
    and why not to get the filename from the same asm code ? example from some var .. or dont know. Imagine that we want to load a file that was selected in a menu. Then we must pass the filename to these routines. How can be this done ?
  • edited June 2010
    arfgh wrote: »
    and why not to get the filename from the same asm code ? example from some var .. or dont know. Imagine that we want to load a file that was selected in a menu. Then we must pass the filename to these routines. How can be this done ?

    Errrm ... use DEF FN to pass arguments to USR routines, as exampled in the listing in #40 above. Check your PMs for a link to the MENU program which I sent you yesterday, which does just that.
  • edited June 2010
    well examining the ams codes on the previous page of this topic, i dont understand where the filename text is passed to the routine. Maybe i dont see because i expected to do all from the asm code with no basic.
  • edited June 2010
    There's an example of its use in the program I sent to you the other day. Specifically, the use of FN o(f$) in these lines:

    10 CLEAR 46999: GO SUB 9120: GO SUB 9134: GO SUB 9220: DEF FN o(f$)=USR 49050: DEF FN p(t,e)=USR 47000
    ...
    900 LET r$=l$(item): IF FN o(r$+CHR$ 255) THEN CLS : LOAD r$

    The USR 49050 routine is the one given in #40 above, with comments explaining how it works. It references the DEFADD system variables area to get the file name passed in the FN o(f$) call.

    If you want to pass the file name from the l$() array to the file check routine all in m/code then you'd have to pick up the program name from j$(), cross-reference the corresponding entry in l$(), then set up the address of that entry in HL so it could be used by the DOS-OPEN routine called from (a slightly modified version of) USR 49050. The file name string referenced by DOS-OPEN has to be terminated with FFh, so either every entry in l$() would need an FFh at the end, or (better) copy the selected one somewhere else and tag on an FFh before setting the address in HL.

    Using m/code to search for variables in the VARS area and select an entry in a string array is also covered in the program which I sent the other day. Using string arrays defined outside of BASIC has been covered in another thread. My work here is done now.
Sign In or Register to comment.