I spent some time today and went thru CCM and PEM and made changes to correct this issue.
In CCM, the parse routine was the issue. In short, it takes the first character in the line, masks off the upper 4 bits, then tests the second character for a colon. If the colon is found, it branches to set the tmpdsk variable with the lower 4-bits from the masked value. This works okay provided you never enter a drive letter (or any ascii character) that is not a valid drive. After this, the tmpdsk value is tested for zero, is it is, any drive change is skipped and the default drive is used. If the value is non-zero, one is subtracted and then saved as the selected drive and PEM is called. This is the main issue with drives responding to invalid drive letters, or any ascii character as the upper 4-bits are stripped off.
In PEM, the change drive routine simply masks off the upper 5-bits and uses the lower 3-bits as the drive number. As other programs loaded into the TEA can also access PEM, any drive number passed to PEM will access drives from 0-7 depending on whatever was passed in the A reg to the PEM call.
The fix is two-fold:
- Change how PEM processes the drive number used in the change drive call. Instead of masking for the lower 3-bits, a compare of the maximum drive is done. If the drive number is too high, PEM now issues a drive out of range message and performs a warm boot. Easy enough.
- Change to CCM for the line parse routine. First strip off the high bit to ensure ascii only. Next if it's a drive change (colon character is second), a test and convert lower case to upper case is done. Once completed, a range check from "A" to "H" is done, any character outside of the range is change to the highest drive letter plus 1 (so it's out of range). After that, the upper 4-bits are masked off (now 0-15 is valid) and saved as tmpdsk. Also pretty easy as a fix.
Initial testing has been successful... doing a dir command or attempting to change the deafult drive using upper or lower case works correctly. All drives respond only to their actual drive letter. Any other character is returned as a drive range error.
the CCM code change is:
Code:
;parse command line
prslin ldx #0 ;clear index
prsmre txa ;save
pha ;index
lda #0 ;clear temp
sta tmpdsk ;drive flag
ldy cnbfpt ;get buffer pointer
jsr skpspc ;find first non-space
sty curpnt ;save index
beq nulchr ;jump if null
;
;the and instruction below is to strip off ascii bits that are drive letter related!
; by doing so, A - H become %0001 - %1000 (1-8), which can be a real problem...
; if the next character is a semicolon (:). that 4-bit masked value becomes the
; TMPDSK variable, which is spliced into the FCB and becomes the selected drive.
; As a result, any ascii character can be entered and you wind up with a list of
; phantom drive letters, depending on what was entered, alpha or not.
;
; The goal here is to mask off the lower 7 bits for true ascii, then let this
; routine below starting at "drvinp" complete the check for a valid drive letter.
;
and #%01111111 ;strip off bit 7 for ascii only
pha ;and save to stack
iny ;point to next char
lda cnstxt,y ;and get it
cmp #':' ;if it's a colon
beq drvinp ;jump and set drive letter
pla ;else clear the stack
dey ;backup index
nulchr lda dfldsk ;set automatic
sta fcbone,x ;to default
bpl trynme ;then parse name
;
;at this stage, we get the ascii character back from the stack, which is the
; assumed drive letter. Now we need to range check this and ensure it's within
; the range of a-z or A-Z. First, we'll convert lower case to upper case, then
; check for the proper range. If the character is outside of the range, we can
; simply set it for the acceptable range plus one. This will be caught by the
; PEM routine and flagged as a drive out of range.
;
drvinp pla ;get the "drive letter" back
cmp #$61 ;check for lower case ascii/control characters
bcc ucok ;if lower, upper case is okay
sbc #$20 ;else subtract $20 to convert to upper case
ucok cmp #'A' ;compare for ascii "A" or higher
bcc baddrv ;branch if too low
cmp #'I' ;check for ascii "I" or higher
bcc drvok ;else branch and set drive
baddrv lda #'I' ;get first out of range drive
drvok and #%00001111 ;mask off upper 4 bits
sta tmpdsk ;else save to temp disk flag
sta fcbone,x ;and into the fcb
iny ;increment past colon, continue parsing
trynme lda #8 ;set name count
and the PEM code change is here:
Code:
;change drive
; input:addinp
; returns:none
; alters:all
xchgdr lda addinp ;get inout
cmp #8 ;check valid range (0-7)
bcs drnger ;if bad, use error below
sta drvcmd ;and save
chgdrv lda drvcmd ;get input
cmp curdrv ;if same as current
beq drvsme ;do nothing
sta curdrv ;else change current
jmp mapdrv ;then log it in
drvsme rts
drnger lda rngmvc ;point to
ldy rngmvc+1 ;select message
jsr sndstr ;and send it
jmp xwboot ;and abort
Code:
;relocatable vectors
.byte $4c
extevc .word extexq-1
.byte $4c
sltmvc .word sltmsg
.byte $4c
rngmvc .word rngmsg
.byte $4c
empdvc .word empty
.byte $4c
rommvc .word romsg
.byte $4c
bdsmvc .word bdsmsg
.byte $4c
pemmvc .word pemmsg
.byte $4c
dcbevc .word dcb
;relocation stopper
.byte $ff
;messages
romsg .byte " - R/O$"
bdsmsg .byte " - BAD SECTOR"
.byte cr,lf,"<RET> TO IGNORE -- <OTHER> "
.byte "TO ABORT$"
pemmsg .byte cr,lf,"PEM ERROR ON $"
sltmsg .byte " - INVALID DRIVE$"
rngmsg .byte cr,lf,"DRIVE OUT OF RANGE$"
I'm still working on a new RAM based version, but the changes above are to the unmodified code from Richard. Sorry about the bad formating... I'm using the original source code, which uses tab characters and spaces mixed.