# STRANGER THINGS ABOUT YOUR APPLE II, part 3 An A2SE series about things you did not know about your Apple II or maybe simply forgot. # Part 3: Inline Text Modes In this article we're going to discover how you can - integrate `FLASH`/`INVERSE`/`NORMAL` commands within strings and strings variables - display `FLASH`/`INVERSE` characters in listings - `PRINT` normally unprintable control-characters in order to plot brown and orange pixels on the lores screen (wtf ?) ## Text modes on the Apple II This is old news: the Apple II support 3 kind of text displays: characters are written on screen either in `NORMAL` mode (white on black), `INVERSE` mode (black on white) or `FLASH` mode (alternating between `NORMAL` and `INVERSE` mode). Three commands allow you to change the text mode. They are `NORMAL`, `INVERSE` and `FLASH`. If you want your text to be printed in inverse, all you have to do is issue an `INVERSE` statement before a `PRINT`: ```basic INVERSE: PRINT "YOU WIN 10 POINTS !" ``` ![Inverse](img/inverse.png) If you don't issue a `NORMAL` command, then all the subsequent `PRINT`s will display text in `INVERSE`. The same goes for `FLASH`. Now, if you want to mix `NORMAL`/`INVERSE`/`FLASH` modes in the same string, your only option is to issue several `PRINT`s and adjust the text mode accordingly in between. ```basic PRINT "YOU WIN "; : INVERSE : PRINT "10"; : NORMAL : PRINT " POINTS !" ``` ![Normal and Inverse](img/normal_inverse.png) ## Integrating text modes within strings This is something that's possible on several 8-bit computers but not on the Apple II, except if you have a 80-column card. In this case, **and** if the card is active, you can use CTRL-O and CTRL-N to instruct the computer that the following characters are respectively in `INVERSE` or `NORMAL` modes. There's no CTRL code for the `FLASH` mode though, as the 80 column cannot display `FLASH` characters. We are going to do exactly the same but without the need for a 80-column card and we will add a CTRL code for the `FLASH` mode too ! The way to do that is rather easy as all we have to do is redirect the character output routine of the Apple II to our own routine. Fortunately, this redirection has been planned from day one in Woz' monitor. This is basically what allows you to print your listings and screens on a printer (and not on screen). This is also how DOS intercepts CTRL-D commands (you know like `PRINT CHR$(4);"CATALOG"` ) and how DOS and PRODOS commands are handled. In `$FDED` is the monitor routine named `COUT`. Its role is to handle the output of characters on screen. But the first thing `COUT` does is give control to another, user-defined, routine, if any. By default (if there's no DOS/PRODOS), this routine is located in `$FDF0` (and is named `COUT1`), that is just 3 bytes after `$FDED` and it's in fact the next instruction after the one in `$FDED`. We have this: ```Assembly FDED: 6C 36 00 COUT JMP (CSWL) ; jump to location referenced by $36-$37 FDF0: 48 COUT1 PHA ; normal monitor character output routine starts here FDF1: ... ``` So, what we need to do is write in CSWL (zero page $36) and CSWH (zero page $37) the address where we want to handle the character output. There, we check if the character that must be output is one of the CTRL characters that will set the `NORMAL`/`INVERSE`/`FLASH` mode, set the mode accordingly and return the control to `$FDF0`. That's for the theory. But remember I also want to print normally unprintable control-characters. ## How Applesoft and the monitor work together. When you type a character on the Apple II keyboard, the character that's been typed is retrievable in `$C000` (decimal `-16384` or `49152` ... that's why you do `K=PEEK(49152)` when you want to identify which key was pressed). You also know that this character is a byte, and that it corresponds to the ASCII code of the character **plus 128** because the hi-bit of the byte is set. This value, if the character is meant to be printed on screen, is sent to `COUT`. Thus, `COUT` expects a byte with a value above 127. Let's see what happens with Applesoft. There are not many routines in Applesoft that output characters. We have `PRINT`. We have `INPUT` (that internally uses `PRINT`). We have `LIST`. We have `TRACE`. We have `TAB()` and `SPC()`. We have error messages too and then we have here and there some routines that output a carriage-return character for various reasons. All these use `COUT`. Thus the first thing that Applesoft does is add 128 to the ASCII value of the character that must be displayed (more precisely, Applesoft applies an ORA-mask on the byte value, forcing the hi-bit to turn on). Now with a byte value above 127, Applesoft then checks if the character is a "control-character", that is a character with an ASCII value below 32. But since the byte value is now above 127, it checks if the value is below 160 (=128+32). If it's NOT a control-character, then Applesoft checks if the `FLASH` mode is on. If it is, then it turns on the 6th bit of the byte (equivalent to add 32), and our byte value is now above 191. Then the byte is sent to `COUT`. So, `COUT` has a value which is either in - range 128 to 159 if a control character is to be output - range 160 to 255 if a `NORMAL` or `INVERSE` character is to be output - range 192 to 255 if a `FLASH` character is to be output The first thing that `COUT` does is modify the byte received: - if `NORMAL` mode is set, the value is not modified. The byte is still **between 128 and 255** - if `INVERSE` mode is set, bits 6 and 7 of the value are set to 0, which is equivalent to - subtract 192 if the byte is above 191, or - subtract 128 if the byte is between 128 and 191. The byte is now **between 0 and 63**. - if `FLASH` mode is set, bit 7 is set to 0, equivalent to subtract 128. The byte is now **between 64 and 127**. - if it's a control character, the value is not modified regardless of the current text mode So we have now 4 possibilities: - Values from 0 to 63 for `INVERSE` output - Values from 64 to 127 for `FLASH` output - Values from 128 to 159 for control characters - Values from 160 to 255 for `NORMAL` output `INVERSE`, `FLASH` and `NORMAL` characters are output on screen accordingly while control-characters are handled separately. For a standard Apple II, only CTRL-G (bell), CTRL-M (return), CTRL-H (backspace or left-arrow) and CTRL-J (line feed or down-arrow) and handled. The others are simply ignored. You can observe the result of each of the 4 possibilities mentioned above. Type ```basic TEXT: HOME VTAB 1: INVERSE: PRINT "A"; : FLASH : PRINT "A"; : NORMAL : PRINT CHR$(1); : PRINT "A"; : VTAB 4 ``` As you can see, the `PRINT CTRL-A` (or more exactly `PRINT CHR$(1)`) did not output anything because `COUT` ignores control-characters. Now type ```basic PRINT PEEK (1024);" ";PEEK(1025);" ";PEEK(1026);" ";PEEK(1027) ``` These are the 4 values of the first 4 characters on the top of the screen. The 1 is A in `INVERSE`, the 65 is A in `FLASH`, the 193 is A in `NORMAL` and the 160 is just the space character in `NORMAL` in the 4th position. The control-character was not printed. ![PRINT multiples A](img/print_a.png) Now let us do the same but without `PRINT`: ```basic TEXT: HOME POKE 1024,1 : POKE 1025, 65: POKE 1026, 129: POKE 1027, 193 ``` ![POKE multiples A](img/poke_a.png) Well ! It looks like we can store values of 128 to 159 on the screen memory even though we cannot PRINT those control-characters. ## Why print control-characters ? Let's admit it, at first sight, there's absolutely no interest in printing control-characters. After all, these characters are designed to be invisible: they're used in communications protocols or to move the cursor, etc. What's more they just look like normal characters when you `POKE` them in screen memory. Well, there's one minor interest though. The text area memory is in $400-$7FF. And this area is shared with the lo-res display. It means we can use `PRINT` to `PLOT` on the lores screen. `PRINT`ing one character actually draws two contiguous vertical lores pixels. For instance, type the following: ```basic GR INVERSE: VTAB 1: PRINT "Q@Q@QAA@Q@@@Q@@@QAQ": PRINT "QAQ@QA@@Q@@@Q@@@Q@Q": PRINT "A@A@AAA@AAA@AAA@AAA": NORMAL: VTAB 22 ``` ![Hello in lores](img/hello.png) You've just drawn the word "HELLO" the fastest possible way with Applesoft only. The problem now is that to `PRINT`/draw all possible combinations of colors you need to be able to `PRINT` all 255 possible values of bytes, including those between 128 to 159, that is the control-characters. As `PRINT` is super-fast compared to `PLOT` (or `HLIN` and `VLIN`), this could be used to display sprites on the lores screen faster than ever with Applesoft. And since what we want to do is use combinations of CTRL-characters to change the text mode **within** strings, we could draw any shape and store the `INVERSE`/`FLASH`/`NORMAL`/`SPECIAL` statements within the string itself ! ## The code explained The routine will be simple and short, so we can store it in $300. But if you want to store it elsewhere, you can as it's completely relocatable. The first thing we want to do is initialize CSWL/CSWH (and thus activate our routine). To do that we can begin in $300 with a simple init routine that needs to be called at the start of your Applesoft program (or at least before you want to take advantage of the new feature). We also want to initialize a flag stating that the "Peculiar mode" is not set yet. The "Peculiar mode" is that new mode where we allow to print control-characters. I decided that this flag would be stored in zero page $34. This memory location is normally used by the monitor (it is known as `YSAV`) to store temp data but I estimated that there would be no interest in being in the monitor AND want to print control-characters on the lores screen. As this is the only zero page location that I need, I wanted to avoid any of the usual "free" zero pages locations to make sure I don't interfere with possibly other programs that might use these "free" locations. So the code begins with: ```Assembly 300: A9 03 INIT LDA #>START 302: 85 37 STA CSWH 304: A9 0D LDA #