Skip to navigation

Elite on the BBC Micro and NES

Version analysis of TT26 / CHPR

This code appears in the following versions (click to see it in the source code):

Code variations between these versions are shown below.

Code variation 1 of 53A variation in the comments only

Tap on a block to expand it, and tap it again to revert.

Name: TT26
Name: CHPR
Type: Subroutine Category: Text Summary: Print a character at the text cursor by poking into screen memory Deep dive: Drawing text
Print a character at the text cursor (XC, YC), do a beep, print a newline, or delete left (backspace).

Code variation 2 of 53A variation in the comments only

Tap on a block to expand it, and tap it again to revert.

WRCHV is set to point here by the loading process.
Calls to OSWRCH will end up here when A is not in the range 128-147, as those are reserved for the special jump table OSWRCH commands.

Arguments: A The character to be printed. Can be one of the following: * 7 (beep)

Code variation 3 of 53A variation in the comments only

Tap on a block to expand it, and tap it again to revert.

* 10-13 (line feeds and carriage returns)
* 10 (line feed) * 11 (clear the top part of the screen and draw a border) * 12-13 (carriage return)
* 32-95 (ASCII capital letters, numbers and punctuation) * 127 (delete the character to the left of the text cursor and move the cursor to the left) XC Contains the text column to print at (the x-coordinate) YC Contains the line number to print on (the y-coordinate)
Returns: A A is preserved X X is preserved Y Y is preserved

Code variation 4 of 53A variation in the comments only

This variation is blank in the 6502 Second Processor version.

C flag The C flag is cleared

Code variation 5 of 53A variation in the comments only

This variation is blank in the 6502 Second Processor and Master versions.

Other entry points:

Code variation 6 of 53A variation in the comments only

This variation is blank in the Disc (flight), Disc (docked), 6502 Second Processor, Master and Electron versions.

RR3+1 Contains an RTS

Code variation 7 of 53A variation in the comments only

This variation is blank in the 6502 Second Processor and Master versions.

RREN Prints the character definition pointed to by P(2 1) at the screen address pointed to by (A SC). Used by the BULB routine

Code variation 8 of 53A variation in the comments only

This variation is blank in the Disc (docked), 6502 Second Processor and Master versions.

rT9 Contains an RTS

Code variation 9 of 53A variation in the comments only

This variation is blank in the Cassette, Disc (flight), 6502 Second Processor, Master and Electron versions.

R5-1 Contains an RTS

Code variation 10 of 53A variation in the comments only

This variation is blank in the Cassette, Disc (flight), Disc (docked) and Electron versions.

Other entry points: RR4 Restore the registers and return from the subroutine

Code variation 11 of 53A variation in the labels only

Tap on a block to expand it, and tap it again to revert.

.TT26
.CHPR

Code variation 12 of 53Minor and very low-impact

Tap on a block to expand it, and tap it again to revert.

STA K3 \ Store the A, X and Y registers, so we can restore STY YSAV2 \ them at the end (so they don't get changed by this STX XSAV2 \ routine)
STA K3 \ Store the A, X and Y registers, so we can restore PHY \ them at the end (so they don't get changed by this PHX \ routine)
STA K3 \ Store the A, X and Y registers, so we can restore TYA \ them at the end (so they don't get changed by this PHA \ routine) TXA PHA LDA K3

Code variation 13 of 53A variation in the labels only

This variation is blank in the Cassette, Disc (flight), 6502 Second Processor, Master and Electron versions.

.RRNEW

Code variation 14 of 53Specific to an individual platform

This variation is blank in the 6502 Second Processor version.

LDY QQ17 \ Load the QQ17 flag, which contains the text printing \ flags

Code variation 15 of 53Minor and very low-impact

This variation is blank in the 6502 Second Processor version.

Tap on a block to expand it, and tap it again to revert.

CPY #255 \ If QQ17 = 255 then printing is disabled, so jump to BEQ RR4 \ RR4, which doesn't print anything, it just restores \ the registers and returns from the subroutine
INY \ If QQ17 = 255 then printing is disabled, so jump to BEQ RR4 \ RR4, which doesn't print anything, it just restores \ the registers and returns from the subroutine
CPY #255 \ If QQ17 = 255 then printing is disabled, so jump to BEQ RR4S \ RR4S (via the JMP in RR4S) to restore the registers \ and return from the subroutine using a tail call

Code variation 16 of 53Related to the Master version

The Master Compact release prints the disc catalogue using different logic, as the Compact uses ADFS rather than DFS.

See below for more variations related to this code.

This variation is blank in the Cassette, Disc (flight), Disc (docked), 6502 Second Processor and Electron versions.

IF _COMPACT TAY \ Copy the character to be printed from A into Y BEQ RR4S \ If the character to be printed is 0 or >= 128, jump to BMI RR4S \ RR4S (via the JMP in RR4S) to restore the registers \ and return from the subroutine using a tail call .RRNEW ENDIF

Code variation 17 of 53Specific to an individual platform

This variation is blank in the Cassette, Disc (flight), Disc (docked), 6502 Second Processor and Electron versions.

LDY #%00001111 \ Set bits 1 and 2 of the Access Control Register at STY VIA+&34 \ SHEILA &34 to switch screen memory into &3000-&7FFF

Code variation 18 of 53Related to the Master version

See variation 16 above for details.

This variation is blank in the Cassette, Disc (flight) and Electron versions.

Tap on a block to expand it, and tap it again to revert.

TAY \ Set Y = the character to be printed BEQ RR4 \ If the character is zero, which is typically a string \ terminator character, jump down to RR4 to restore the \ registers and return from the subroutine BMI RR4 \ If A > 127 then there is nothing to print, so jump to \ RR4 to restore the registers and return from the \ subroutine
TAY \ Set Y = the character to be printed IF _SNG47 BEQ RR4S \ If the character is zero, which is typically a string \ terminator character, jump down to RR4 (via the JMP in \ RR4S) to restore the registers and return from the \ subroutine using a tail call BMI RR4S \ If A > 127 then there is nothing to print, so jump to \ RR4 (via the JMP in RR4S) to restore the registers and \ return from the subroutine ELIF _COMPACT LDX CATF \ If CATF <> 0, skip the following two instructions, as BNE P%+6 \ we are printing a disc catalogue and we don't want any \ control characters lurking in the catalogue to trigger \ the screen clearing routine ENDIF
TAY \ Set Y = the character to be printed BEQ RR4S \ If the character is zero, which is typically a string \ terminator character, jump down to RR4 (via the JMP in \ RR4S) to restore the registers and return from the \ subroutine using a tail call

Code variation 19 of 53Related to an advanced feature

The advanced versions support an extra control code in the standard text token system: control code 11 clears the screen.

This variation is blank in the Cassette, Disc (flight), Disc (docked) and Electron versions.

CMP #11 \ If this is control code 11 (clear screen), jump to cls BEQ cls \ to clear the top part of the screen, draw a white \ border and return from the subroutine via RR4

Code variation 20 of 53Minor and very low-impact

Tap on a block to expand it, and tap it again to revert.

CMP #7 \ If this is a beep character (A = 7), jump to R5, BEQ R5 \ which will emit the beep, restore the registers and \ return from the subroutine
CMP #7 \ If this is not control code 7 (beep), skip the next BNE P%+5 \ instruction JMP R5 \ This is control code 7 (beep), so jump to R5 to make \ a beep and return from the subroutine via RR4
 CMP #32                \ If this is an ASCII character (A >= 32), jump to RR1
 BCS RR1                \ below, which will print the character, restore the
                        \ registers and return from the subroutine

 CMP #10                \ If this is control code 10 (line feed) then jump to
 BEQ RRX1               \ RRX1, which will move down a line, restore the
                        \ registers and return from the subroutine

Code variation 21 of 53Specific to an individual platform

The cassette version uses control code 12 for a newline, while the other versions use 13.

Tap on a block to expand it, and tap it again to revert.

LDX #1 \ If we get here, then this is control code 11-13, of STX XC \ which only 13 is used. This code prints a newline,
LDX #1 \ If we get here, then this is control code 12 or 13, STX XC \ both of which are used. This code prints a newline,
                        \ which we can achieve by moving the text cursor
                        \ to the start of the line (carriage return) and down
                        \ one line (line feed). These two lines do the first
                        \ bit by setting XC = 1, and we then fall through into
                        \ the line feed routine that's used by control code 10

Code variation 22 of 53Specific to an individual platform

This variation is blank in the Cassette, Disc (flight), 6502 Second Processor, Master and Electron versions.

CMP #13 \ If this is control code 13 (carriage return) then jump BEQ RR4 \ RR4 to restore the registers and return from the \ subroutine
.RRX1

Code variation 23 of 53Minor and very low-impact

Tap on a block to expand it, and tap it again to revert.

INC YC \ Print a line feed, simply by incrementing the row \ number (y-coordinate) of the text cursor, which is \ stored in YC BNE RR4 \ Jump to RR4 to restore the registers and return from \ the subroutine (this BNE is effectively a JMP as Y \ will never be zero)
CMP #13 \ If this is control code 13 (carriage return) then jump BEQ RR4S \ to RR4 (via the JMP in RR4S) to restore the registers \ and return from the subroutine using a tail call INC YC \ Increment the text cursor y-coordinate to move it \ down one row .RR4S JMP RR4 \ Jump to RR4 to restore the registers and return from \ the subroutine using a tail call
.RR1

                        \ If we get here, then the character to print is an
                        \ ASCII character in the range 32-95. The quickest way
                        \ to display text on-screen is to poke the character
                        \ pixel by pixel, directly into screen memory, so
                        \ that's what the rest of this routine does
                        \
                        \ The first step, then, is to get hold of the bitmap
                        \ definition for the character we want to draw on the
                        \ screen (i.e. we need the pixel shape of this
                        \ character). The MOS ROM contains bitmap definitions
                        \ of the system's ASCII characters, starting from &C000
                        \ for space (ASCII 32) and ending with the £ symbol
                        \ (ASCII 126)

Code variation 24 of 53A variation in the comments only

This variation is blank in the Cassette, Disc (flight), Disc (docked), Master and Electron versions.

\ \ To save time looking this information up from the MOS \ ROM a copy of these bitmap definitions is embedded \ into this source code at page FONT%, so page 0 of the \ font is at FONT%, page 1 is at FONT%+1, and page 2 at \ FONT%+3
                        \
                        \ There are definitions for 32 characters in each of the
                        \ three pages of MOS memory, as each definition takes up
                        \ 8 bytes (8 rows of 8 pixels) and 32 * 8 = 256 bytes =
                        \ 1 page. So:
                        \
                        \   ASCII 32-63  are defined in &C000-&C0FF (page 0)
                        \   ASCII 64-95  are defined in &C100-&C1FF (page 1)
                        \   ASCII 96-126 are defined in &C200-&C2F0 (page 2)
                        \
                        \ The following code reads the relevant character

Code variation 25 of 53A variation in the comments only

This variation is blank in the Master version.

Tap on a block to expand it, and tap it again to revert.

\ bitmap from the above locations in ROM and pokes
\ bitmap from the copied MOS bitmaps at FONT% and pokes
                        \ those values into the correct position in screen
                        \ memory, thus printing the character on-screen
                        \
                        \ It's a long way from 10 PRINT "Hello world!":GOTO 10

Code variation 26 of 53A variation in the comments only

This variation is blank in the Disc (flight), Disc (docked), 6502 Second Processor, Master and Electron versions.

\LDX #LO(K3) \ These instructions are commented out in the original \INX \ source, but they call OSWORD 10, which reads the \STX P+1 \ character bitmap for the character number in K3 and \DEX \ stores it in the block at K3+1, while also setting \LDY #HI(K3) \ P+1 to point to the character definition. This is \STY P+2 \ exactly what the following uncommented code does, \LDA #10 \ just without calling OSWORD. Presumably the code \JSR OSWORD \ below is faster than using the system call, as this \ version takes up 15 bytes, while the version below \ (which ends with STA P+1 and SYX P+2) is 17 bytes. \ Every efficiency saving helps, especially as this \ routine is run each time the game prints a character \ \ If you want to switch this code back on, uncomment \ the above block, and comment out the code below from \ TAY to STX P+2. You will also need to uncomment the \ LDA YC instruction a few lines down (in RR2), just to \ make sure the rest of the code doesn't shift in \ memory. To be honest I can't see a massive difference \ in speed, but there you go

Code variation 27 of 53Specific to an individual platform

This variation is blank in the Disc (flight), Disc (docked) and Master versions.

TAY \ Copy the character number from A to Y, as we are \ about to pull A apart to work out where this \ character definition lives in memory
                        \ Now we want to set X to point to the relevant page

Code variation 28 of 53A variation in the comments only

This variation is blank in the Master version.

Tap on a block to expand it, and tap it again to revert.

\ number for this character - i.e. &C0, &C1 or &C2.
\ number for this character - i.e. FONT% to FONT%+2
                        \ The following logic is easier to follow if we look
                        \ at the three character number ranges in binary:
                        \
                        \   Bit #  76543210
                        \
                        \   32  = %00100000     Page 0 of bitmap definitions
                        \   63  = %00111111
                        \
                        \   64  = %01000000     Page 1 of bitmap definitions
                        \   95  = %01011111
                        \
                        \   96  = %01100000     Page 2 of bitmap definitions
                        \   125 = %01111101
                        \
                        \ We'll refer to this below

Code variation 29 of 53Specific to an individual platform

This variation is blank in the Cassette, Disc (flight), Disc (docked), Master and Electron versions.

\BEQ RR4 \ This instruction is commented out in the original \ source, but it would return from the subroutine if A \ is zero BPL P%+5 \ If the character number is positive (i.e. A < 128) \ then skip the following instruction JMP RR4 \ A >= 128, so jump to RR4 to restore the registers and \ return from the subroutine using a tail call

Code variation 30 of 53Specific to an individual platform

Tap on a block to expand it, and tap it again to revert.

LDX #&BF \ Set X to point to the first font page in ROM minus 1, \ which is &C0 - 1, or &BF
LDX #(FONT%-1) \ Set X to point to the page before the first font page, \ which is FONT% - 1
 ASL A                  \ If bit 6 of the character is clear (A is 32-63)
 ASL A                  \ then skip the following instruction
 BCC P%+4

Code variation 31 of 53Specific to an individual platform

Tap on a block to expand it, and tap it again to revert.

LDX #&C1 \ A is 64-126, so set X to point to page &C1
LDX #(FONT%+1) \ A is 64-126, so set X to point to page FONT% + 1
 ASL A                  \ If bit 5 of the character is clear (A is 64-95)
 BCC P%+3               \ then skip the following instruction

 INX                    \ Increment X
                        \

Code variation 32 of 53A variation in the comments only

This variation is blank in the Master version.

Tap on a block to expand it, and tap it again to revert.

\ By this point, we started with X = &BF, and then \ we did the following: \ \ If A = 32-63: skip then INX so X = &C0 \ If A = 64-95: X = &C1 then skip so X = &C1 \ If A = 96-126: X = &C1 then INX so X = &C2 \
\ By this point, we started with X = FONT%-1, and then \ we did the following: \ \ If A = 32-63: skip then INX so X = FONT% \ If A = 64-95: X = FONT%+1 then skip so X = FONT%+1 \ If A = 96-126: X = FONT%+1 then INX so X = FONT%+2 \
                        \ In other words, X points to the relevant page. But
                        \ what about the value of A? That gets shifted to the
                        \ left three times during the above code, which
                        \ multiplies the number by 8 but also drops bits 7, 6
                        \ and 5 in the process. Look at the above binary
                        \ figures and you can see that if we cleared bits 5-7,
                        \ then that would change 32-53 to 0-31... but it would
                        \ do exactly the same to 64-95 and 96-125. And because
                        \ we also multiply this figure by 8, A now points to
                        \ the start of the character's definition within its
                        \ page (because there are 8 bytes per character
                        \ definition)
                        \
                        \ Or, to put it another way, X contains the high byte
                        \ (the page) of the address of the definition that we
                        \ want, while A contains the low byte (the offset into
                        \ the page) of the address

Code variation 33 of 53Minor and very low-impact

Tap on a block to expand it, and tap it again to revert.

STA P+1 \ Store the address of this character's definition in STX P+2 \ P(2 1)
STA P \ Store the address of this character's definition in STX P+1 \ P(1 0)
STA Q \ R is the same location as Q+1, so this stores the STX R \ address of this character's definition in Q(1 0)

Code variation 34 of 53Related to the screen mode

This variation is blank in the Cassette, Disc (flight), Disc (docked), 6502 Second Processor and Master versions.

LDA #128 \ Set SC = 128 for use in the calculation below STA SC LDA YC \ If YC < 24 then we are in the top part of the screen, CMP #24 \ so skip the following two instructions BCC P%+8 JSR TTX66 \ We are off the bottom of the screen, so we don't want \ to print anything, so first clear the screen and draw \ a white border JMP RR4 \ Jump to RR4 to restore the registers and return from \ the subroutine \ The text row is on-screen, so now to calculate the \ screen address we need to write to, as follows: \ \ SC = &5800 + (char row * 256) + (char row * 64) + 32 \ \ See the deep dive on "Drawing pixels in the Electron \ version" for details LSR A \ Set (A SC) = (A SC) / 4 ROR SC \ = (4 * ((char row * 64) + 32)) / 4 LSR A \ = char row * 64 + 32 ROR SC ADC YC \ Set SC(1 0) = (A SC) + (YC 0) + &5800 ADC #&58 \ = (char row * 64 + 32) STA SC+1 \ + char row * 256 \ + &5800 \ \ which is what we want, so SC(1 0) contains the address \ of the first visible pixel on the character row we \ want
 LDA XC                 \ Fetch XC, the x-coordinate (column) of the text cursor
                        \ into A

Code variation 35 of 53Related to an enhanced feature

The standard disc catalogue is just too wide to fit into Elite's special square screen mode, so when printing the catalogue in the enhanced versions, a space is removed from column 17, which is always a blank column in the middle of the catalogue.

This variation is blank in the Cassette, Disc (flight) and Electron versions.

Tap on a block to expand it, and tap it again to revert.

LDX CATF \ If CATF = 0, jump to RR5, otherwise we are printing a BEQ RR5 \ disc catalogue CPY #' ' \ If the character we want to print in Y is a space, BNE RR5 \ jump to RR5 \ If we get here, then CATF is non-zero, so we are \ printing a disc catalogue and we are not printing a \ space, so we drop column 17 from the output so the \ catalogue will fit on-screen (column 17 is a blank \ column in the middle of the catalogue, between the \ two lists of filenames, so it can be dropped without \ affecting the layout). Without this, the catalogue \ would be one character too wide for the square screen \ mode (it's 34 characters wide, while the screen mode \ is only 33 characters across) CMP #17 \ If A = 17, i.e. the text cursor is in column 17, jump BEQ RR4 \ to RR4 to restore the registers and return from the \ subroutine, thus omitting this column .RR5
LDX CATF \ If CATF = 0, jump to RR5, otherwise we are printing a BEQ RR5 \ disc catalogue IF _SNG47 CPY #' ' \ If the character we want to print in Y is a space, BNE RR5 \ jump to RR5 \ If we get here, then CATF is non-zero, so we are \ printing a disc catalogue and we are not printing a \ space, so we drop column 17 from the output so the \ catalogue will fit on-screen (column 17 is a blank \ column in the middle of the catalogue, between the \ two lists of filenames, so it can be dropped without \ affecting the layout). Without this, the catalogue \ would be one character too wide for the square screen \ mode (it's 34 characters wide, while the screen mode \ is only 33 characters across) CMP #17 \ If A = 17, i.e. the text cursor is in column 17, jump BEQ RR4 \ to RR4 to restore the registers and return from the \ subroutine, thus omitting this column ELIF _COMPACT CMP #21 \ If A < 21, i.e. the text cursor is in column 0-20, BCC RR5 \ jump to RR5 to skip the following \ If we get here, then CATF is non-zero, so we are \ printing a disc catalogue and we have reached column \ 21, so we move to the start of the next line so the \ catalogue line-wraps to fit within the bounds of the \ screen INC YC \ More the text cursor down a line LDA #1 \ Move the text cursor to column 1 STA XC ENDIF .RR5

Code variation 36 of 53Related to the screen mode

Tap on a block to expand it, and tap it again to revert.

ASL A \ Multiply A by 8, and store in SC. As each character is ASL A \ 8 pixels wide, and the special screen mode Elite uses ASL A \ for the top part of the screen is 256 pixels across STA SC \ with one bit per pixel, this value is not only the \ screen address offset of the text cursor from the left \ side of the screen, it's also the least significant \ byte of the screen address where we want to print this \ character, as each row of on-screen pixels corresponds \ to one page. To put this more explicitly, the screen \ starts at &6000, so the text rows are stored in screen \ memory like this: \ \ Row 1: &6000 - &60FF YC = 1, XC = 0 to 31 \ Row 2: &6100 - &61FF YC = 2, XC = 0 to 31 \ Row 3: &6200 - &62FF YC = 3, XC = 0 to 31 \ \ and so on
ASL A \ Multiply A by 8, and store in SC, so we now have: ASL A \ ASL A \ SC = XC * 8 STA SC
ASL A \ Multiply A by 8, and add to SC. As each character is ASL A \ 8 pixels wide, this gives us the screen address of the ASL A \ character block where we want to print this character ADC SC STA SC BCC P%+4 \ If the addition of the low byte overflowed, increment INC SC+1 \ the high byte

Code variation 37 of 53Specific to an individual platform

This variation is blank in the Cassette, Disc (docked), 6502 Second Processor, Master and Electron versions.

INC XC \ Move the text cursor to the right by 1 column

Code variation 38 of 53Related to the screen mode

This variation is blank in the Electron version.

LDA YC \ Fetch YC, the y-coordinate (row) of the text cursor

Code variation 39 of 53Specific to an individual platform

This variation is blank in the Disc (flight) version.

CPY #127 \ If the character number (which is in Y) <> 127, then BNE RR2 \ skip to RR2 to print that character, otherwise this is \ the delete character, so continue on DEC XC \ We want to delete the character to the left of the \ text cursor and move the cursor back one, so let's \ do that by decrementing YC. Note that this doesn't \ have anything to do with the actual deletion below, \ we're just updating the cursor so it's in the right \ position following the deletion

Code variation 40 of 53Specific to an individual platform

This variation is blank in the Disc (flight) version.

Tap on a block to expand it, and tap it again to revert.

ADC #&5E \ A contains YC (from above) and the C flag is set (from TAX \ the CPY #127 above), so these instructions do this: \ \ X = YC + &5E + 1 \ = YC + &5F \ Because YC starts at 0 for the first text row, this \ means that X will be &5F for row 0, &60 for row 1 and \ so on. In other words, X is now set to the page number \ for the row before the one containing the text cursor, \ and given that we set SC above to point to the offset \ in memory of the text cursor within the row's page, \ this means that (X SC) now points to the character \ above the text cursor
ASL A \ A contains YC (from above), so this sets A = YC * 2 ASL SC \ Double the low byte of SC(1 0), catching bit 7 in the \ C flag. As each character is 8 pixels wide, and the \ special screen mode Elite uses for the top part of the \ screen is 256 pixels across with two bits per pixel, \ this value is not only double the screen address \ offset of the text cursor from the left side of the \ screen, it's also the least significant byte of the \ screen address where we want to print this character, \ as each row of on-screen pixels corresponds to two \ pages. To put this more explicitly, the screen starts \ at &4000, so the text rows are stored in screen \ memory like this: \ \ Row 1: &4000 - &41FF YC = 1, XC = 0 to 31 \ Row 2: &4200 - &43FF YC = 2, XC = 0 to 31 \ Row 3: &4400 - &45FF YC = 3, XC = 0 to 31 \ \ and so on ADC #&3F \ Set X = A TAX \ = A + &3F + C \ = YC * 2 + &3F + C
DEC SC+1 \ Decrement the high byte of the screen address to point \ to the address of the current character, minus one \ page

Code variation 41 of 53Specific to an individual platform

This variation is blank in the Disc (flight) version.

Tap on a block to expand it, and tap it again to revert.

LDY #&F8 \ Set Y = &F8, so the following call to ZES2 will count \ Y upwards from &F8 to &FF JSR ZES2 \ Call ZES2, which zero-fills from address (X SC) + Y to \ (X SC) + &FF. (X SC) points to the character above the \ text cursor, and adding &FF to this would point to the \ cursor, so adding &F8 points to the character before \ the cursor, which is the one we want to delete. So \ this call zero-fills the character to the left of the \ cursor, which erases it from the screen
\ Because YC starts at 0 for the first text row, this \ means that X will be &3F for row 0, &41 for row 1 and \ so on. In other words, X is now set to the page number \ for the row before the one containing the text cursor, \ and given that we set SC above to point to the offset \ in memory of the text cursor within the row's page, \ this means that (X SC) now points to the character \ above the text cursor LDY #&F0 \ Set Y = &F0, so the following call to ZES2 will count \ Y upwards from &F0 to &FF JSR ZES2 \ Call ZES2, which zero-fills from address (X SC) + Y to \ (X SC) + &FF. (X SC) points to the character above the \ text cursor, and adding &FF to this would point to the \ cursor, so adding &F0 points to the character before \ the cursor, which is the one we want to delete. So \ this call zero-fills the character to the left of the \ cursor, which erases it from the screen
LDY #&F8 \ Set Y = &F8, so the following call to ZES2 will count \ Y upwards from &F8 to &FF JSR ZES2 \ Call ZES2, which zero-fills from address SC(1 0) + Y \ to SC(1 0) + &FF. SC(1 0) points to the address of the \ current character, minus one page, and adding &FF to \ this would point to the cursor, so adding &F8 points \ to the character before the cursor, which is the one \ we want to delete. So this call zero-fills the \ character to the left of the cursor, which erases it \ from the screen

Code variation 42 of 53Specific to an individual platform

This variation is blank in the Disc (flight) version.

BEQ RR4 \ We are done deleting, so restore the registers and \ return from the subroutine (this BNE is effectively \ a JMP as ZES2 always returns with the Z flag set) .RR2 \ Now to actually print the character INC XC \ Once we print the character, we want to move the text \ cursor to the right, so we do this by incrementing \ XC. Note that this doesn't have anything to do \ with the actual printing below, we're just updating \ the cursor so it's in the right position following \ the print

Code variation 43 of 53A variation in the comments only

This variation is blank in the Disc (flight), Disc (docked), 6502 Second Processor, Master and Electron versions.

\LDA YC \ This instruction is commented out in the original \ source. It isn't required because we only just did a \ LDA YC before jumping to RR2, so this is presumably \ an example of the authors squeezing the code to save \ 2 bytes and 3 cycles \ \ If you want to re-enable the commented block near the \ start of this routine, you should uncomment this \ instruction as well

Code variation 44 of 53Related to the screen mode

Tap on a block to expand it, and tap it again to revert.

CMP #24 \ If the text cursor is on the screen (i.e. YC < 24, so BCC RR3 \ we are on rows 0-23), then jump to RR3 to print the \ character
EQUB &2C \ Skip the next instruction by turning it into \ &2C &85 &08, or BIT &0885, which does nothing apart \ from affect the flags. We skip the instruction as we \ already set the value of SC+1 above

Code variation 45 of 53Specific to an individual platform

This variation is blank in the Electron version.

Tap on a block to expand it, and tap it again to revert.

JSR TTX66 \ Otherwise we are off the bottom of the screen, so \ clear the screen and draw a white border JMP RR4 \ And restore the registers and return from the \ subroutine
PHA \ Store A on the stack so we can retrieve it below JSR TTX66 \ Otherwise we are off the bottom of the screen, so \ clear the screen and draw a white border PLA \ Retrieve A from the stack... only to overwrite it with \ the next instruction, so presumably we didn't need to \ preserve it and this and the PHA above have no effect LDA K3 \ Set A to the character to be printed JMP RRNEW \ Jump back to RRNEW to print the character
JSR TT66 \ Otherwise we are off the bottom of the screen, so \ clear the screen and draw a white border JMP RR4 \ And restore the registers and return from the \ subroutine
IF _SNG47 JSR TTX66 \ Otherwise we are off the bottom of the screen, so \ clear the screen and draw a white border LDA #%00001111 \ Set bits 1 and 2 of the Access Control Register at STA VIA+&34 \ SHEILA &34 to switch screen memory into &3000-&7FFF ELIF _COMPACT LDA CATF \ If CATF = 0, skip the next two instructions, as we are BEQ P%+7 \ not printing a disc catalogue JSR RETURN \ We have just printed the disc catalogue, so wait until BPL P%-3 \ RETURN is pressed, looping indefinitely until it gets \ tapped JSR TTX66 \ Call TTX66 to clear the screen ENDIF LDA #1 \ Move the text cursor to column 1, row 1 STA XC STA YC LDA K3 \ Set A to the character to be printed, though again \ this has no effect, as the following call to RR4 does \ the exact same thing IF _SNG47 JMP RR4 \ And restore the registers and return from the \ subroutine ELIF _COMPACT JMP RRNEW \ Jump back to RRNEW to print the character ENDIF
PHA \ Store A on the stack so we can retrieve it below JSR TTX66 \ Otherwise we are off the bottom of the screen, so \ clear the screen and draw a white border LDA #1 \ Move the text cursor to column 1, row 1 STA XC STA YC PLA \ Retrieve A from the stack... only to overwrite it with \ the next instruction, so presumably we didn't need to \ preserve it and this and the PHA above have no effect LDA K3 \ Set A to the character to be printed, though again \ this has no effect, as the following call to RR4 does \ the exact same thing JMP RR4 \ And restore the registers and return from the \ subroutine
.RR3

                        \ A contains the value of YC - the screen row where we
                        \ want to print this character - so now we need to
                        \ convert this into a screen address, so we can poke
                        \ the character data to the right place in screen
                        \ memory

Code variation 46 of 53Related to the screen mode

This variation is blank in the Electron version.

Tap on a block to expand it, and tap it again to revert.

ORA #&60 \ We already stored the least significant byte \ of this screen address in SC above (see the STA SC \ instruction above), so all we need is the most \ significant byte. As mentioned above, in Elite's \ square mode 4 screen, each row of text on-screen \ takes up exactly one page, so the first row is page \ &60xx, the second row is page &61xx, so we can get \ the page for character (XC, YC) by OR'ing with &60. \ To see this in action, consider that our two values \ are, in binary: \ \ YC is between: %00000000 \ and: %00010111 \ &60 is: %01100000 \ \ so YC OR &60 effectively adds &60 to YC, giving us \ the page number that we want
ASL A \ Set A = 2 * A \ = 2 * YC ASL SC \ Back in RR5 we set SC = XC * 8, so this does the \ following: \ \ SC = SC * 2 \ = XC * 16 \ \ so SC contains the low byte of the screen address we \ want to poke the character into, as each text \ character is 8 pixels wide, and there are four pixels \ per byte, so the offset within the row's 512 bytes \ is XC * 8 pixels * 2 bytes for each 8 pixels = XC * 16 ADC #&40 \ Set A = &40 + A \ = &40 + (2 * YC) \ \ so A contains the high byte of the screen address we \ want to poke the character into, as screen memory \ starts at &4000 (page &40) and each screen row takes \ up 2 pages (512 bytes)
.RREN

 STA SC+1               \ Store the page number of the destination screen
                        \ location in SC+1, so SC now points to the full screen
                        \ location where this character should go

Code variation 47 of 53Related to the screen mode

This variation is blank in the Cassette, Disc (flight), Disc (docked) and Electron versions.

Tap on a block to expand it, and tap it again to revert.

LDA SC \ Set P(3 2) = SC(1 0) + 8 CLC \ ADC #8 \ starting with the low bytes STA P+2 LDA SC+1 \ And then adding the high bytes, so P(3 2) points to STA P+3 \ the character block after the one pointed to by \ SC(1 0)
LDA SC \ Set (T S) = SC(1 0) + 8 CLC \ ADC #8 \ starting with the low bytes STA S LDA SC+1 \ And then adding the high bytes, so (T S) points to the STA T \ character block after the one pointed to by SC(1 0), \ and because T = S+1, we have: \ \ S(1 0) = SC(1 0) + 8
 LDY #7                 \ We want to print the 8 bytes of character data to the
                        \ screen (one byte per row), so set up a counter in Y
                        \ to count these bytes

.RRL1

Code variation 48 of 53Related to the screen mode

Tap on a block to expand it, and tap it again to revert.

LDA (P+1),Y \ The character definition is at P(2 1) - we set this up \ above - so load the Y-th byte from P(2 1), which will \ contain the bitmap for the Y-th row of the character
\ We print the character's 8-pixel row in two parts, \ starting with the first four pixels (one byte of \ screen memory), and then the second four (a second \ byte of screen memory) LDA (P),Y \ The character definition is at P(1 0) - we set this up \ above - so load the Y-th byte from P(1 0), which will \ contain the bitmap for the Y-th row of the character AND #%11110000 \ Extract the high nibble of the character definition \ byte, so the first four pixels on this row of the \ character are in the first nibble, i.e. xxxx 0000 \ where xxxx is the pattern of those four pixels in the \ character STA W \ Set A = (A >> 4) OR A LSR A \ LSR A \ which duplicates the high nibble into the low nibble LSR A \ to give xxxx xxxx LSR A ORA W AND COL \ AND with the colour byte so that the pixels take on \ the colour we want to draw (i.e. A is acting as a mask \ on the colour byte)
\ We print the character's 8-pixel row in two parts, \ starting with the first four pixels (one byte of \ screen memory), and then the second four (a second \ byte of screen memory) LDA (Q),Y \ The character definition is at Q(1 0) - we set this up \ above - so load the Y-th byte from Q(1 0), which will \ contain the bitmap for the Y-th row of the character AND #%11110000 \ Extract the high nibble of the character definition \ byte, so the first four pixels on this row of the \ character are in the first nibble, i.e. xxxx 0000 \ where xxxx is the pattern of those four pixels in the \ character STA U \ Set A = (A >> 4) OR A LSR A \ LSR A \ which duplicates the high nibble into the low nibble LSR A \ to give xxxx xxxx LSR A ORA U AND COL \ AND with the colour byte so that the pixels take on \ the colour we want to draw (i.e. A is acting as a mask \ on the colour byte)

Code variation 49 of 53Specific to an individual platform

When we are docked in the disc version, we don't need to worry about displaying text on the space view, so we don't have to implement EOR logic when printing, and instead can use OR logic.

Tap on a block to expand it, and tap it again to revert.

EOR (SC),Y \ If we EOR this value with the existing screen \ contents, then it's reversible (so reprinting the \ same character in the same place will revert the \ screen to what it looked like before we printed \ anything); this means that printing a white pixel \ onto a white background results in a black pixel, but \ that's a small price to pay for easily erasable text
ORA (SC),Y \ OR this value with the current contents of screen \ memory, so the pixels we want to draw are set
 STA (SC),Y             \ Store the Y-th byte at the screen address for this
                        \ character location

Code variation 50 of 53Related to the screen mode

This variation is blank in the Cassette, Disc (flight), Disc (docked) and Electron versions.

Tap on a block to expand it, and tap it again to revert.

\ We now repeat the process for the second batch of four \ pixels in this character row LDA (P),Y \ Fetch the bitmap for the Y-th row of the character \ again AND #%00001111 \ This time we extract the low nibble of the character \ definition, to get 0000 xxxx STA W \ Set A = (A << 4) OR A ASL A \ ASL A \ which duplicates the low nibble into the high nibble ASL A \ to give xxxx xxxx ASL A ORA W AND COL \ AND with the colour byte so that the pixels take on \ the colour we want to draw (i.e. A is acting as a mask \ on the colour byte) EOR (P+2),Y \ EOR this value with the existing screen contents of \ P(3 2), which is equal to SC(1 0) + 8, the next four \ pixels along from the first four pixels we just \ plotted in SC(1 0) STA (P+2),Y \ Store the Y-th byte at the screen address for this \ character location
\ We now repeat the process for the second batch of four \ pixels in this character row LDA (Q),Y \ Fetch the bitmap for the Y-th row of the character \ again AND #%00001111 \ This time we extract the low nibble of the character \ definition, to get 0000 xxxx STA U \ Set A = (A << 4) OR A ASL A \ ASL A \ which duplicates the low nibble into the high nibble ASL A \ to give xxxx xxxx ASL A ORA U AND COL \ AND with the colour byte so that the pixels take on \ the colour we want to draw (i.e. A is acting as a mask \ on the colour byte) EOR (S),Y \ EOR this value with the existing screen contents of \ S(1 0), which is equal to SC(1 0) + 8, the next four \ pixels along from the first four pixels we just \ plotted in SC(1 0) STA (S),Y \ Store the Y-th byte at the screen address for this \ character location
 DEY                    \ Decrement the loop counter

 BPL RRL1               \ Loop back for the next byte to print to the screen

.RR4

Code variation 51 of 53Minor and very low-impact

Tap on a block to expand it, and tap it again to revert.

LDY YSAV2 \ We're done printing, so restore the values of the LDX XSAV2 \ A, X and Y registers that we saved above and clear LDA K3 \ the C flag, so everything is back to how it was CLC
LDA #%00001001 \ Clear bits 1 and 2 of the Access Control Register at STA VIA+&34 \ SHEILA &34 to switch main memory back into &3000-&7FFF PLX \ We're done printing, so restore the values of the PLY \ A, X and Y registers that we saved above and clear the LDA K3 \ C flag, so everything is back to how it was CLC
PLA \ We're done printing, so restore the values of the TAX \ A, X and Y registers that we saved above, so PLA \ everything is back to how it was TAY LDA K3

Code variation 52 of 53A variation in the labels only

This variation is blank in the Disc (docked) and Master versions.

.rT9
 RTS                    \ Return from the subroutine

.R5

Code variation 53 of 53Related to Elite's use of the Tube

Tap on a block to expand it, and tap it again to revert.

JSR BEEP \ Call the BEEP subroutine to make a short, high beep JMP RR4 \ Jump to RR4 to restore the registers and return from \ the subroutine using a tail call
LDX #LO(BELI) \ Set (Y X) to point to the parameter block below LDY #HI(BELI) JSR OSWORD \ We call this from above with A = 7, so this calls \ OSWORD 7 to make a short, high beep JMP RR4 \ Jump to RR4 to restore the registers and return from \ the subroutine using a tail call .BELI EQUW &0012 \ The SOUND block for a short, high beep: EQUW &FFF1 \ EQUW &00C8 \ SOUND &12, -15, &C8, &02 EQUW &0002 \ \ This makes a sound with flush control 1 on channel 2, \ and with amplitude &F1 (-15), pitch &C8 (200) and \ duration &02 (2). This is a louder, higher and longer \ beep than that generated by the NOISE routine with \ A = 32 (a short, high beep)