This shows you the differences between two versions of the page.
— |
base:detect_drives_on_iec_bus [2015-04-17 04:31] (current) |
||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Providing Multiple Drive Support via Machine Language ====== | ||
+ | By Todd S. Elliott (eyeth@erols.com) | ||
+ | March 16, 1998 | ||
+ | |||
+ | [See also Commodore World #22 for a similar routine] | ||
+ | |||
+ | First, many thanks to Maurice Randall for providing the addresses in drive | ||
+ | ROMs of various disk drives for the purposes of determining each drive. The | ||
+ | info was largely adapted from the BASIC drive polling routines written by | ||
+ | Doug Cotton. Many thanks also goes to Doug Cotton for writing a well written | ||
+ | and comprehensive two-part article on serial bus programming appearing in | ||
+ | Commodore World #10 and #11. It has taken a lot of pain and frustration out | ||
+ | of serial bus programming. | ||
+ | |||
+ | Before we go any further, Doug Cotton recently stated in a comp.sys.cbm | ||
+ | article about Desterm v3.0's problems of serial device polling. Doug stated | ||
+ | that Mark Fellows found out that sending a ' | ||
+ | SuperGrafix *Gold* on serial device #14 will lock up the serial bus. Thus, | ||
+ | the routine would need to ignore polling of device #14, and allow the user | ||
+ | of your program the option of forcing the polling of device #14 for any | ||
+ | attached serial device. (Of course, warn the user of such dangers.) | ||
+ | |||
+ | Now, with the thanks out of the way, let's get right into the bits and | ||
+ | nybbles of the program. First, it creates a drive buffer at the cassette | ||
+ | buffer beginning at $0334, and zeroes it out. The .Y register serves as a | ||
+ | device index; a value of 8 in .Y equals device 8, 9 in .Y equals device 9 and | ||
+ | so on, up to 30 for a permissible range of devices from 8 to 30. | ||
+ | |||
+ | Next, it quickly determines whether a serial device is attached at devices | ||
+ | #8-#30. if there is a serial device, the program will then put in a value | ||
+ | equal to the serial device at the buffer indexed by an appropriate .Y device | ||
+ | index. This value will be changed later in the drive polling routine. | ||
+ | |||
+ | The drive polling routine then checks the values within the buffer indexed by | ||
+ | .Y serving as a serial device number. If a non-zero value is found, then | ||
+ | there is a serial device present and the program then reads in the addresses | ||
+ | in drive ROMs. The program checks the drive ROMs for the appropriate | ||
+ | identifiers to correctly determine which drive it is. | ||
+ | |||
+ | Once it has identified the drive, it inserts a byte representation of that | ||
+ | drive into the buffer, indexed by .Y serving as a device number. The program | ||
+ | repeats, until there are no more available drives for identification. | ||
+ | |||
+ | At the end of the routine, the drive buffer, indexed by .Y as a device | ||
+ | number, should contain byte representations of various drives at various | ||
+ | device numbers. This serves as a ' | ||
+ | program then can freely use this information to offer multiple drive support | ||
+ | with specific device support such as partitions, subdirectories, | ||
+ | drive RAM for buffers, and more. | ||
+ | |||
+ | Let's offer my system as an example: | ||
+ | dev #08- Internal 1571 | ||
+ | dev #09- External 1571 | ||
+ | dev #10- FD 4000 | ||
+ | dev #11- CMD HD 85 | ||
+ | dev #12- RAMLink | ||
+ | |||
+ | After running the routine below, the drives buffer contains the following | ||
+ | values: | ||
+ | .Y as device index = value (decimal) | ||
+ | 08 = 71 | ||
+ | 09 = 71 | ||
+ | 10 = 224 | ||
+ | 11 = 192 | ||
+ | 12 = 128 | ||
+ | 13 = 0 | ||
+ | ...[so on] | ||
+ | 30 = 0 | ||
+ | |||
+ | Read also the comments liberally sprinkled throughout the code to gain | ||
+ | further insight into this routine. There is minimal error checking in the | ||
+ | following routine, so it is good practice to implement such checking. | ||
+ | |||
+ | Enjoy. | ||
+ | < | ||
+ | ============================================================================= | ||
+ | ; polls all available drives | ||
+ | ; By Todd S. Elliott | ||
+ | ; Buddy assembler format | ||
+ | ; Feel free to use the routine without any attribution. | ||
+ | |||
+ | ; Compiler equates | ||
+ | ; zero page | ||
+ | ldv = $fb; last device number that LOADed the program | ||
+ | status = $90; status register | ||
+ | dv = $ba; current device number- arbitrary location | ||
+ | |||
+ | ; equates | ||
+ | drives = $032c; buffer for the drive poll routine- arbitrary location | ||
+ | second = $ff93 | ||
+ | tksa = $ff96 | ||
+ | acptr = $ffa5 | ||
+ | ciout = $ffa8 | ||
+ | untalk = $ffab | ||
+ | unlstn = $ffae | ||
+ | listen = $ffb1 | ||
+ | talk = $ffb4 | ||
+ | readst = $ffb7 | ||
+ | setlfs = $ffba | ||
+ | setnam = $ffbd | ||
+ | open = $ffc0 | ||
+ | close = $ffc3 | ||
+ | chkin = $ffc6 | ||
+ | chkout = $ffc9 | ||
+ | clrchn = $ffcc | ||
+ | chrin = $ffcf | ||
+ | chrout = $ffd2 | ||
+ | load = $ffd5 | ||
+ | save = $ffd8 | ||
+ | getin = $ffe4 | ||
+ | clall = $ffe7 | ||
+ | |||
+ | ; program code begins here | ||
+ | |||
+ | *= $c000; arbitrary starting address | ||
+ | |||
+ | ldy #23 | ||
+ | lda #$00 | ||
+ | - sta drives+8,y; zero out the drive buffer | ||
+ | dey | ||
+ | bpl - | ||
+ | |||
+ | ; this way, a zero indicates that a drive is not present in that address | ||
+ | ; referenced by the .Y index. For example- .Y equals 10, and if that address | ||
+ | ; in ' | ||
+ | ; no drive attached. | ||
+ | |||
+ | lda dv; get current device and save it temporarily | ||
+ | sta ldv; device from which it was LOADed- Obviously will work if this | ||
+ | ; routine was called first before any disk activity. Use this | ||
+ | ; routine as part of the initalization sequence of your program. | ||
+ | ; Otherwise, it is not necessary to use it in this routine. | ||
+ | lda #$08; start with device #8 and finish at #30 | ||
+ | sta dv; create a new device number | ||
+ | - ldy #$00 | ||
+ | sty status; clear the status register | ||
+ | jsr listen; opens the device for listening | ||
+ | lda #$ff; Secondary address - $0f OR'ed with $f0 to open | ||
+ | jsr second; opens the channel with sa of 15 | ||
+ | lda status; check the status byte | ||
+ | bpl +; branch if there is a device present | ||
+ | ; obviously, some kind of error- restore original device | ||
+ | - jsr unlstn; severs the serial bus control | ||
+ | |||
+ | ; The following sub-routine was ' | ||
+ | ; the drive polling with or without the commented sub-routine will work | ||
+ | ; correctly. The reason why I left it there is because Commodore World # | ||
+ | ; articles on serial bus routines recommended such an anal-retentive | ||
+ | ; sequence. I'm sure it is for a good reason though. If you can spare the | ||
+ | ; room, feel free to use the commented routine by removing the semi-colons. | ||
+ | |||
+ | ; lda #$00 | ||
+ | ; sta status; clear the status register | ||
+ | ; lda dv; get device number | ||
+ | ; jsr listen; opens the device for listening | ||
+ | ; lda #$ef; sa - $0f and OR'ed with $e0 to close file | ||
+ | ; jsr second; closes the channel with sa of 15 | ||
+ | ; jsr unlstn; finally closes it | ||
+ | inc dv; increment device number | ||
+ | lda dv | ||
+ | cmp #31; is it device 31? if so, finish drive polling | ||
+ | bne -- | ||
+ | beq ++; relative JMP | ||
+ | + ldy dv | ||
+ | tya | ||
+ | sta drives,y; store in successful device number | ||
+ | ; remember, .Y is the device index | ||
+ | bne -; relative JMP | ||
+ | |||
+ | + ldy #14 | ||
+ | disable polling of serial device #14 | ||
+ | lda #$00 | ||
+ | sta drives,y | ||
+ | |||
+ | ldy #$08; get drive info (And if in 128 mode, delete the plus (+) sign.) | ||
+ | l1 lda drives,y | ||
+ | bne + | ||
+ | iny | ||
+ | cpy #31; are we done? (acceptable range of 8 to 30) | ||
+ | bne l1 | ||
+ | rts; exits the whole drive polling routine | ||
+ | + sta dv; set device number | ||
+ | jsr open' | ||
+ | ldx #< | ||
+ | ldy #> | ||
+ | jsr open' | ||
+ | |||
+ | jsr chrin | ||
+ | cmp #70; is it ' | ||
+ | bne + | ||
+ | jsr chrin; get next character | ||
+ | cmp #68; is it ' | ||
+ | bne l2 | ||
+ | ldy dv; get device number | ||
+ | lda #$e0; indicates that it is a FD drive at device number | ||
+ | jmp get' | ||
+ | |||
+ | + cmp #72; is it ' | ||
+ | bne + | ||
+ | jsr chrin; get next character | ||
+ | cmp #68; is it ' | ||
+ | bne l2 | ||
+ | ldy dv; get device number | ||
+ | lda #$c0; indicates that it is a HD drive at device number | ||
+ | bne get' | ||
+ | |||
+ | + cmp #82; is it ' | ||
+ | bne l2 | ||
+ | jsr chrin; get next character | ||
+ | cmp #68; is it ' | ||
+ | bne + | ||
+ | ldy dv; get device number | ||
+ | lda #$f0; indicates that it is a RD drive at device number | ||
+ | bne get' | ||
+ | + cmp #76; is it ' | ||
+ | bne l2 | ||
+ | ldy dv; get device number | ||
+ | lda #$80; indicates that it is a RLdrive at device number | ||
+ | bne get' | ||
+ | |||
+ | l2 =*; check for CBM devices | ||
+ | jsr close' | ||
+ | jsr open' | ||
+ | ldx #< | ||
+ | ldy #> | ||
+ | jsr open' | ||
+ | |||
+ | jsr chrin; gets the drive info | ||
+ | cmp #53; is it ' | ||
+ | bne l3 | ||
+ | jsr chrin; gets the next number | ||
+ | cmp #52; is it ' | ||
+ | bne + | ||
+ | ldy dv; get device number | ||
+ | lda #41; indicates a 1541 at that device number | ||
+ | bne get' | ||
+ | + cmp #55; is it ' | ||
+ | bne l3 | ||
+ | ldy dv; get device number | ||
+ | lda #71; indicates a 1571 at that device number | ||
+ | bne get' | ||
+ | |||
+ | l3 =*; polls for a 1581 drive | ||
+ | jsr close' | ||
+ | jsr open' | ||
+ | ldx #< | ||
+ | ldy #> | ||
+ | jsr open' | ||
+ | |||
+ | jsr chrin; gets the drive info | ||
+ | cmp #53; is it a ' | ||
+ | bne l4 | ||
+ | jsr chrin; gets the next drive number | ||
+ | cmp #56; is it a ' | ||
+ | bne l4 | ||
+ | ldy dv; gets device number | ||
+ | lda #81; indicates a 1581 at that device number | ||
+ | bne get' | ||
+ | |||
+ | l4 =*; foreign drive- just mark it as foreign | ||
+ | ldy dv; get device number | ||
+ | lda #$01; indicates a foreign device number | ||
+ | bne get' | ||
+ | |||
+ | close' | ||
+ | jsr clrchn | ||
+ | lda #$0f; lfn | ||
+ | jsr close; and closes it | ||
+ | rts | ||
+ | |||
+ | ; gets the next drive on the serial bus | ||
+ | ; First, it stores the byte representation of a drive into the ' | ||
+ | ; buffer indexed by .Y showing the device number. | ||
+ | |||
+ | ; Available byte representations- | ||
+ | ; 00 - No serial device available | ||
+ | ; 01 - foreign drive (MSD, Excelerator, | ||
+ | ; 41 - 1541 drive | ||
+ | ; 71 - 1571 drive | ||
+ | ; 81 - 1581 drive | ||
+ | ; e0 - FD drive | ||
+ | ; c0 - HD drive | ||
+ | ; f0 - RD drive | ||
+ | ; 80 - RAMLink | ||
+ | |||
+ | ; Note - the high bit set indicates a CMD drive, whereas the high bit cleared | ||
+ | ; indicates a CBM drive. | ||
+ | |||
+ | get' | ||
+ | sta drives,y | ||
+ | jsr close' | ||
+ | ldy dv | ||
+ | iny; increment table offset | ||
+ | jmp l1 | ||
+ | |||
+ | ; opens the command channel and issues a command | ||
+ | open' | ||
+ | lda #$0f; lfn | ||
+ | tay; sa for command channel | ||
+ | ldx dv | ||
+ | jsr setlfs; set up the open sequence | ||
+ | lda #$07; length of command (m-r command) | ||
+ | rts | ||
+ | |||
+ | open' | ||
+ | jsr setnam; sends the command | ||
+ | jsr open; opens the file | ||
+ | ldx #$0f; lfn | ||
+ | jsr chkin; redirect input | ||
+ | rts | ||
+ | |||
+ | cmdinfo =*; gets CMD drive info | ||
+ | ; at $fea4 in drive ROM | ||
+ | .asc " | ||
+ | .byte $a4, | ||
+ | |||
+ | cbminfo =*; gets CBM drive info | ||
+ | ; at $e5c5 in drive ROM | ||
+ | .asc " | ||
+ | .byte $c5, | ||
+ | |||
+ | info1581 =*; gets 1581 drive info | ||
+ | ; at $a6e8 in drive ROM | ||
+ | .asc " | ||
+ | .byte $e8, | ||
+ | |||
+ | ; end file drivepoll | ||
+ | </ |