Jump to content
IGNORED

How to re-map a drive via firmware?


Recommended Posts

Has anyone re-mapped a drive via firmware?

 

In the XL/XE OS, any calls to SIO first go through PIO.  So, in theory, a parallel device should be able to re-map disk drives.  Thus far, I have this partially working.

 

My theory is that since Atari uses $31 in DDEVIC and DUNIT is the drive number that it should be possible to, via a parallel card, swap out DUNIT to another drive number and be able to re-map the drives.

 

i.e.  DDEVIC $31, DUNIT 4 (D4:) is called but you'd like to map D4: to physical D2:  The firmware, on a parallel device, should be able to swap out DUNIT 4 for DUNIT 2 then return without handling anything else.  So, the SIO would pick this up and access D2:.

 

To do this, it appears that DUNIT is also stored on the stack prior to calling an parallel device as the OS R2 source code shows:

 

;**    PIO - Parallel Input/Output
;*
;*    ENTRY    JSR    PIO
;*
;*    NOTES
;*        Problem: in the CRASS65 section, CRITIC was:
;*        zero-page.
;*
;*    MODS
;*        Y. M. Chen    02/18/83
;*        1. Bring closer to Coding Standard (object unchanged).
;*           R. K. Nordin    11/01/83


PIO    =    *    ;entry

;    Initialize.

    LDA    #1
;    STA    CRITIC    ;indicate critical section
    .BYTE    $8D, low CRITIC, high CRITIC ;originally VFD
    LDA    DUNIT    ;device unit number
    PHA        ;save device unit number
    LDA    PDVMSK    ;device selection mask
    BEQ    PIO2    ;if no device to select

;    For each device, pass request to device I/O routine:

    LDX    #TPDSL    ;offset to first byte beyond table

PIO1    JSR    SNP    ;select next parallel device
    BEQ    PIO2    ;if no device selected

    TXA
    PHA        ;save offset
    JSR    PDIOV    ;perform parallel device I/O
    PLA        ;saved offset
    TAX        ;restore offset
    BCC    PIO1    ;if device did not field request

;    Restore Floating Point Package.

    LDA    #$00    ;select FPP (deselect device)
    STA    SHPDVS    ;device select shadow
    STA    PDVS    ;device select
    BEQ    PIO3    ;exit

;    Perform SIO.

PIO2    JSR    SIO    ;perform SIO

;    Exit.

PIO3    PLA        ;saved device unit number
    STA    DUNIT    ;restore device unit number
    LDA    #0
;    STA    CRITIC    ;indicate non-critical section
    .BYTE    $8D, low CRITIC, high CRITIC ;originally VFD
    STY    DSTATS
    LDY    DSTATS    ;status (re-establish N)
    RTS        ;return

 

 

 

 

So, part of my parallel device code swaps out DUNIT as follows:

 

 

 

; Re-map physical drives
; On entry, Device ID is in A
RDREMP = *
                TAX                                    ; Move device ID to X
            
                LDA    #low RDDMAP    ; Setup page 0 pointer
                STA    RDA1
                LDA    #high RDDMAP
                STA    RDA2

                TXA                                    ; Load A with Device ID
                LDY    #$04                        ; Index on Y
RDRMP1            
                DEY                                    ; Set value of Y
                CMP    (RDA1),Y                ; Compare Device ID with new Device ID
                BEQ    RDRMP2                ; If DUNIT = new DUNIT, map it
                CPY    #$00                        ; If no match found, exit.
                BEQ    RDRMP4                                            ; skip unmapping device for debugging....was RDRMP3
                JMP    RDRMP1

RDRMP2
                INY                                        ; Y is the new DUNIT

                PLA                                    ; Get the low byte of the return address
                STA    RDA3                        ; Save it
                PLA                                    ; Get the high byte of the return address
                STA    RDA4                        ; Save it
                PLA                                    ; Get DUNIT and discard it.
                TYA                                    ; Put the new DUNIT on the stack
                PHA
                LDA    RDA4                        ; Put the high byte of the return address back
                PHA
                LDA    RDA3                        ; Put the low byte of the return address back
                PHA

                JMP    RDRMP4
;                CLC                                    ; Clear carry to indicate I/O not handled by the RAM Disk
;                RTS

 

 

 

This starts to work but still has problems.  Altirra's Performance Analyzer shows that repeated calls are made to the emulated physical device until it responds.  When it responds, the directory has the wrong number of sectors reported.  Has anyone tried this before?  Am I missing something somewhere?

 

Thanks!

 

 

 

 

 

 

 

Link to comment
Share on other sites

2 hours ago, E474 said:

The UnoCart uses a modified Altirra OS which remaps calls to D1 to the SD card on the UnoCart. The modified code is in (IIRC) : https://github.com/robinhedwards/UnoCart/blob/master/source/Atari/UnoCartOS/pio.s

 

Interesting.  However, I am trying to remap the drives with a stock OS as the card will run on a 1090XL.

Link to comment
Share on other sites

There is indeed precedent for doing this -- the 1450XLD parallel disk drive firmware does it.

 

;===============================================================================
; SIO vector
;
D8F9: AD 4F 02          LDA $024F
D8FC: C9 FF             CMP #$FF
D8FE: F0 28             BEQ $D928
D900: AD 00 03          LDA DDEVIC          ;Get device
D903: 18                CLC                 ;Add unit
D904: 6D 01 03          ADC DUNIT           ; "
D907: 38                SEC                 ;Subtract $32 (D1: + 1, since no unit-1)
D908: E9 32             SBC #$32            ; "
D90A: 90 1C             BCC $D928           ;Exit not handled if <D1:
D90C: C9 08             CMP #$08            ;Check if above D8:
D90E: B0 18             BCS $D928           ;Exit not handled if >D8:
D910: AA                TAX                 ;Use as index
D911: AD 48 02          LDA SHPDVS          ;Load current PBI device
D914: DD 08 D6          CMP $D608,X         ;Check against PBI device table
D917: F0 11             BEQ $D92A           ;Proceed if match
D919: CD 4F 02          CMP $024F           ;
D91C: D0 0A             BNE $D928
D91E: AD 01 03          LDA DUNIT           ;Get device unit
D921: 38                SEC                 ;Reduce by PBI device count
D922: ED 4E 02          SBC $024E           ; "
D925: 8D 01 03          STA DUNIT           ;Update device unit
D928: 18                CLC                 ;Not handled
D929: 60                RTS

 

Of course, if you are testing in Altirra, you will need to either disable disk SIO patch or switch it to PBI mode so it can see the modified DUNIT value.

 

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

18 minutes ago, phaeron said:

There is indeed precedent for doing this -- the 1450XLD parallel disk drive firmware does it.

 

;===============================================================================
; SIO vector
;
D8F9: AD 4F 02          LDA $024F
D8FC: C9 FF             CMP #$FF
D8FE: F0 28             BEQ $D928
D900: AD 00 03          LDA DDEVIC          ;Get device
D903: 18                CLC                 ;Add unit
D904: 6D 01 03          ADC DUNIT           ; "
D907: 38                SEC                 ;Subtract $32 (D1: + 1, since no unit-1)
D908: E9 32             SBC #$32            ; "
D90A: 90 1C             BCC $D928           ;Exit not handled if <D1:
D90C: C9 08             CMP #$08            ;Check if above D8:
D90E: B0 18             BCS $D928           ;Exit not handled if >D8:
D910: AA                TAX                 ;Use as index
D911: AD 48 02          LDA SHPDVS          ;Load current PBI device
D914: DD 08 D6          CMP $D608,X         ;Check against PBI device table
D917: F0 11             BEQ $D92A           ;Proceed if match
D919: CD 4F 02          CMP $024F           ;
D91C: D0 0A             BNE $D928
D91E: AD 01 03          LDA DUNIT           ;Get device unit
D921: 38                SEC                 ;Reduce by PBI device count
D922: ED 4E 02          SBC $024E           ; "
D925: 8D 01 03          STA DUNIT           ;Update device unit
D928: 18                CLC                 ;Not handled
D929: 60                RTS

 

Of course, if you are testing in Altirra, you will need to either disable disk SIO patch or switch it to PBI mode so it can see the modified DUNIT value.

 

This looks more like a device is selected based upon DUNIT.  This differs from what I am doing as I am trying to use a parallel device to intercept and change the DUNIT value.

 

I played around with Altirra's configuration with no effect.  Here's the config:

 

altirr_config_screen.thumb.jpg.a027db091b2e23637088c16153e8791e.jpg

 

I always wondered why I can't just turn off the SIO exceleration mode....

 

I am not sure making those changes would do anything as I've hacked this OS so that I can use it for development.  So, the PIO routine is hacked to just run the RAM Disk functions as so....

 

PIO    =    *    ;entry

;    Initialize.

    LDA    #1
;    STA    CRITIC    ;indicate critical section
    .BYTE    $8D, low CRITIC, high CRITIC ;originally VFD
    LDA    DUNIT    ;device unit number
    PHA        ;save device unit number

 

;;    LDA    PDVMSK    ;device selection mask
;;    BEQ    PIO2    ;if no device to select

;    For each device, pass request to device I/O routine:

;;    LDX    #TPDSL    ;offset to first byte beyond table

;;PIO1    JSR    SNP    ;select next parallel device
;;    BEQ    PIO2    ;if no device selected

;;    TXA
;;    PHA        ;save offset
;;;    JSR    PDIOV    ;perform parallel device I/O
JSR RDISK            ; ************************  RAM DISK CODE
;;    PLA        ;saved offset
;;    TAX        ;restore offset
;;    BCC    PIO1    ;if device did not field request
BCC    PIO2    ; if device did not field request

;    Restore Floating Point Package.

;;    LDA    #$00    ;select FPP (deselect device)
;;    STA    SHPDVS    ;device select shadow
;;    STA    PDVS    ;device select
;;    BEQ    PIO3    ;exit
JMP  PIO3


;    Perform SIO.

PIO2    JSR    SIO    ;perform SIO

;    Exit.

PIO3    PLA        ;saved device unit number
    STA    DUNIT    ;restore device unit number
    LDA    #0
;    STA    CRITIC    ;indicate non-critical section
    .BYTE    $8D, low CRITIC, high CRITIC ;originally VFD
    STY    DSTATS
    LDY    DSTATS    ;status (re-establish N)
    RTS        ;return

 

 

 

 

I figure that once the RAM Disk code is working, it's any easy job to convert it to a PBI device.   🙂

 

 

 

 

 

 

 

 

Link to comment
Share on other sites

49 minutes ago, reifsnyderb said:

This looks more like a device is selected based upon DUNIT.  This differs from what I am doing as I am trying to use a parallel device to intercept and change the DUNIT value.

No, it also modifies DUNIT. Look at the end of the routine. If DUNIT doesn't correspond to one of the devices that the PBI firmware handles, it subtracts off that number of drives so the next unit number accesses SIO D1:.

 

49 minutes ago, reifsnyderb said:

I played around with Altirra's configuration with no effect.  Here's the config:

 

altirr_config_screen.thumb.jpg.a027db091b2e23637088c16153e8791e.jpg

 

I always wondered why I can't just turn off the SIO exceleration mode....

You don't have any SIO device patches enabled, so the acceleration mode won't do anything. It only takes effect if you have one of the SIO patches checked.

 

Link to comment
Share on other sites

10 minutes ago, phaeron said:

No, it also modifies DUNIT. Look at the end of the routine. If DUNIT doesn't correspond to one of the devices that the PBI firmware handles, it subtracts off that number of drives so the next unit number accesses SIO D1:.

Ok, I see it now.  However, if the OS would take control then the OS would take the DUNIT value off of the stack and put it back in DUNIT.  I also checked the 1450XLD OS with OS R2 and both have identical PIO functions as follows:

 

;**    PIO - Parallel Input/Output
;*
;*    ENTRY    JSR    PIO
;*
;*    NOTES
;*        Problem: in the CRASS65 section, CRITIC was:
;*        zero-page.
;*
;*    MODS
;*        Y. M. Chen    02/18/83
;*        1. Bring closer to Coding Standard (object unchanged).
;*           R. K. Nordin    11/01/83


PIO    =    *    ;entry

;    Initialize.

    LDA    #1
;    STA    CRITIC    ;indicate critical section
    .BYTE    $8D, low CRITIC, high CRITIC ;originally VFD
    LDA    DUNIT    ;device unit number
    PHA        ;save device unit number
    LDA    PDVMSK    ;device selection mask
    BEQ    PIO2    ;if no device to select

;    For each device, pass request to device I/O routine:

    LDX    #TPDSL    ;offset to first byte beyond table

PIO1    JSR    SNP    ;select next parallel device
    BEQ    PIO2    ;if no device selected

    TXA
    PHA        ;save offset
    JSR    PDIOV    ;perform parallel device I/O
    PLA        ;saved offset
    TAX        ;restore offset
    BCC    PIO1    ;if device did not field request

;    Restore Floating Point Package.

    LDA    #$00    ;select FPP (deselect device)
    STA    SHPDVS    ;device select shadow
    STA    PDVS    ;device select
    BEQ    PIO3    ;exit

;    Perform SIO.

PIO2    JSR    SIO    ;perform SIO

;    Exit.

PIO3    PLA        ;saved device unit number
    STA    DUNIT    ;restore device unit number
    LDA    #0
;    STA    CRITIC    ;indicate non-critical section
    .BYTE    $8D, low CRITIC, high CRITIC ;originally VFD
    STY    DSTATS
    LDY    DSTATS    ;status (re-establish N)
    RTS        ;return

 

 

PIO is where DUNIT is put on the stack, the device firmware is then excecuted, and PIO3, above, is where the DUNIT value is taken off of the stack and stored into DUNIT.

 

My thought is that to re-map the drives, the DUNIT value needs to be removed from the stack and replaced with a new value like I did here:

 

RDRMP2
                INY                                        ; Y is the new DUNIT

                PLA                                    ; Get the low byte of the return address
                STA    RDA3                        ; Save it
                PLA                                    ; Get the high byte of the return address
                STA    RDA4                        ; Save it
                PLA                                    ; Get DUNIT and discard it.
                TYA                                    ; Put the new DUNIT on the stack
                PHA
                LDA    RDA4                        ; Put the high byte of the return address back
                PHA
                LDA    RDA3                        ; Put the low byte of the return address back
                PHA

                JMP    RDRMP4

 

 

 

Unfortunately, this only partial works.  The drive is re-mapped but certain things aren't quite right.  The number of sectors returned is wrong and it takes several SIO requests for the emulated drive to respond.  I've been using the Performance Analyzer to try to find the problem but it's a needle in the proverbial haystack.

 

 

10 minutes ago, phaeron said:

You don't have any SIO device patches enabled, so the acceleration mode won't do anything. It only takes effect if you have one of the SIO patches checked.

Good to know.  I didn't realize it was related to the SIO patches, above.  Now it makes sense.   🙂

 

Link to comment
Share on other sites

4 hours ago, reifsnyderb said:

PIO is where DUNIT is put on the stack, the device firmware is then excecuted, and PIO3, above, is where the DUNIT value is taken off of the stack and stored into DUNIT.

Sure, but it's restored in the epilogue right before returning to user code, after the regular code runs to send the request out to the SIO bus. The parallel disk device doesn't eat the request, so it falls through to the rest of the PBI devices which also don't, and then it calls the regular SIO code at PIO2 before DUNIT is restored. The caller won't see a change in DUNIT, but the request sent out on the SIO bus will.

 

  • Thanks 1
Link to comment
Share on other sites

5 hours ago, phaeron said:

Sure, but it's restored in the epilogue right before returning to user code, after the regular code runs to send the request out to the SIO bus. The parallel disk device doesn't eat the request, so it falls through to the rest of the PBI devices which also don't, and then it calls the regular SIO code at PIO2 before DUNIT is restored. The caller won't see a change in DUNIT, but the request sent out on the SIO bus will.

 

Ok, I just read and re-read what you wrote and looked at the PIO code again.  For some stupid reason, I mis-read the PIO code.  😞  I was thinking that PIO took DUNIT from the stack before calling SIO.  So, I only put the new DUNIT value on the stack and didn't bother over-writing DUNIT itself.  I was wrongly thinking PIO would overwrite DUNIT, using the stack value, no matter what I did....then spent hours trying to figure out why my code wasn't working correctly.  But it partly worked, so that added to the confusion.

 

So, the good news is I added one extra line of code to overwrite DUNIT and it now works and re-maps the drive!

 

Thank you!

 

Below is the code to store the re-mapped DUNIT....

 

RDRMP2
                INY                                        ; Y is the new DUNIT

                PLA                                    ; Get the low byte of the return address
                STA    RDA3                        ; Save it
                PLA                                    ; Get the high byte of the return address
                STA    RDA4                        ; Save it
                PLA                                    ; Get DUNIT and discard it.
                TYA                                    ; Put the new DUNIT on the stack
                PHA
                LDA    RDA4                        ; Put the high byte of the return address back
                PHA
                LDA    RDA3                        ; Put the low byte of the return address back
                PHA

                STY    DUNIT                    ; Overwrite DUNIT with new DUNIT value.

                JMP    RDRMP4

Edited by reifsnyderb
Link to comment
Share on other sites

I just realized that by changing the DUNIT value, in the stack, might break the "illusion" of re-mapping the drives by providing the real drive to any software that checks the DUNIT value after the SIO request is made.  So, I now think the stack should be left alone and just DUNIT changed.  

 

For example:

 

RDRMP2
                INY                                        ; Y is the new DUNIT

                  STY    DUNIT                    ; Overwrite DUNIT with new DUNIT value.

                JMP    RDRMP4

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...