TL;DR
How did the Apple IIe convert commands to upper case?
Background
I've been using the Virtual ][ emulator in Apple IIe mode (with an Apple IIe Enhanced ROM).
After getting the ELIZA code from Why did BASIC programs tend to READ a redundant copy of DATA? and chopping it about1 to get it to run on the emulator, I realised that some lower to upper case conversion would be useful... but Applesoft BASIC doesn't seem to have any case conversion functions.
I've been playing around with the code below, which I found on Handling Upper and Lower Case on Apple Computers2 , to make all input become uppercase (via CALL802
):
100 REM TEST PROGRAM
110 FOR SPOT=768 TO 825:READ CODE:POKE SPOT, CODE:NEXT
120 DATA 169,9,133,54,169,3,133,55,96,134,6,174,179,251,224,234,208,11,201,225,48,7,201,251,16,3,56,233,32,166,6,76,240,253,169,43,133,56,169,3,133,57,96,32,27,253,201,225,48,7,201,251,16,3,56,233,32,96
130 HOME
140 CALL 768: REM USE PR#0 TO CANCEL
150 PRINT "After a CALL 768 is executed, this"
160 PRINT:PRINT "program will display only upper case"
170 PRINT:PRINT "on an Apple ][ Plus."
180 PRINT:PRINT:PRINT:PRINT
190 CALL 802: REM USE IN#0 TO CANCEL
200 PRINT "Once a CALL 802 is executed, input will"
210 PRINT : PRINT "automatically be converted to upper"
220 PRINT: PRINT "case on any kind of Apple computer."
230 PRINT:INPUT I$
240 PRINT: PRINT I$
For anyone who is interested, the assembly code is in the footnote3.
Commands converted to uppercase
However, I then noted that A touch of Applesoft BASIC (1986), on page 30, states:
You can use both uppercase and lowercase characters, but the computer converts all letters to uppercase.
I then saw in this answer to What are the differences between the versions of AppleSoft BASIC?, that the Apple IIe Enhanced (1985) was the first version that...
Allowed entry of lowercase commands
Therefore, in the Apple IIe Enhanced ROM there must be already a call to convert lowercase to uppercase.
I can't find a decent dissection nor disassembly of a IIe Enhanced ROM. I've only found this one for the Apple II+ (from Apple II ROM Disassembly) - which won't include the functionality because it is too early.
Questions
- Where is this code?
- How is it done and does anyone have an assembly listing?
- Is there a hook to this routine that can be called from BASIC?
Footnotes
1 Primarily, by removing UPPER$
as this doesn't exist in Applesoft BASIC (and REM
ming out the first line (line 10)).
2 Note that the browser will moan about a lack of certificates.
3 The assembler for the POKE
d code above is as follows:
0000: 1 **********************************
0000: 2 * *
0000: 3 * Routines for handling upper &. *
0000: 4 * lower case on Apple ][ Plus, *
0000: 5 * //e, and //c computers *
0000: 6 * *
0000: 7 **********************************
0000: 8 *
0036: 9 CWSL EQU $36 ;output hook
0038: 10 KWSL EQU $38 ;input hook
FDF0: 11 COUT EQU $FDF0 ;sends character to screen
FB83: 12 IDBYTE EQU $FB83 ;test for model of Apple
FD1B: 13 KEYIN EQU $FD18 ;routine to get keystroke
0006: 14 SAVEX EQU $06 ;temporary storage
----- NEXT OBJECT FILE IS I/O.OBJ0
0300: 15 ORG $300
0300: 16 *
0300: 17 **** This routine handles screen output.
0300: 18 *
0300:A9 09 19 HOOKOUT LDA #>OUT ;Hook routine
0302:85 36 20 STA CWSL ;called 'OUT'
0304:A9 03 21 LDA #<OUT ;to handle output
0306:85 37 22 STA CWSL+1
0308:60 23 RTS
0309:86 06 24 OUT STX SAVEX ;Save X-register
030B:AE 83 FB 25 LDX IDBYTE ;Is this computer a
030E:E0 EA 26 CPX #$EA ;][ Plus?
0310:D0 0B 27 BNE SEND ;No.
0312:C9 E1 28 CMP #$E1 ;Check whether
0314:30 07 29 BMI SEND ;character is
0316:C9 FB 30 CMP #$FB ;lower case
0318:10 03 31 BPL SEND
031A:38 32 SEC ;Make lower case into
031B:E9 20 33 SBC #$20 ;upper case.
031D:A6 06 34 SEND LDX SAVEX ;Restores X-register
031F:4C F0 FD 35 JMP COUT ;Send character to screen.
0322: 36 *
0322: 37 **** This routine handles keyboard input.
0322: 38 *
0322:A9 28 39 HOOKIN LDA #>IN ;Hook routine
0324:85 38 40 STA KWSL ;called 'IN'
0326:A6 03 41 LDA #<IN ;to handle input.
0328:85 39 42 STA KWSL+1
032A:60 43 RTS
032B:20 1B FD 44 IN JSR KEYIN ;Get a keystroke.
032E:C9 E1 45 CMP #$E1 ;Check whether
0330:30 07 46 BMI RETURN ;character is
0332:C9 FB 47 CMP #$FB ;lower case.
0334:10 03 48 BPL RETURN
0336:38 49 SEC ;Make lower case into
0337:E9 20 50 SBC #$20 ;upper case.
0339:60 51 RETURN RTS
(c-'a') > (unsigned)25
for a single branch, or non-destructive cmp/branch twice to check the range. e.g. for x86, Converting Uppercase to Lowercase in Assembly issue is the other direction, using OR to set a bit instead of AND to clear. As you say, ASCII is designed to make case-flipping easy with^= 32
or|
or&
to set or clear