_0ADC_PO_STORE (exit here after any change in the print position due to cursor moves, position controllers, scrolling orprinting of characters, to put the new values in the system variables relating to the screen or printer: BC holds line and column numbers of the_last print position, HL the pixel address of the first byte of the next character position) if bit 1 of FLAGS is set jump on to PO ST PR; output to the ZX printer - if bit zero of TV FLAG is set jump on to PO ST E; output to the lower screen - (upper screen) put the position values in 5C88 S POSN - put the pixel address in 5C84 DF CC - return. _0AF0_PO_ST_E (lower screen): put the position values in 5C8A S POSNL and 5C82 ECHO E - put the pixel address in 5C86 DF CCL - return. _0AFC_PO_ST_PR (ZX printer): put the column number in 5C7F P POSN; there is no line number - put the pixel address in 5C80 PR CC - return. _0B03_PO_FETCH (a free-standing subroutine, but only called in the PRINT OUT block: from PRINT OUT, PO COMMA - an unnecessary call - PO FILL, PO ANY; also the apparent exit from PRINT OUT, but its return is to another PRINT OUT routine): if bit 1 of FLAGS is set jump on to PO F PR; output to the ZX printer - get the upper screen print position from 5C88 S POSN and the display address from 5C84 DF CC - if bit zero of TV FLAG is not set, return; output to the upper screen - (lower screen) get the print position from 5C8A S POSNL and the display address from 5C86 DF CCL - return. _0B1D_PO_F_PR (ZX printer): get the column number from 5C7F P POSN and the print buffer address from 5C80 PR CC - return. _0B24_PO_ANY (formally a free-standing subroutine, but only called from PO ABLE; A holds a code to be output): if the code is less than 80h/128d jump on to PO CHAR; a single character - if the code is more than 8Fh/143d jump on to PO T&UDG;a token or user-defined graphic - (the code is one of the keyboard graphics 80h/128d to 8Fh/143d) call PO GR 1 to construct the graphic form in the calculator memory area - call PO FETCH to recover the print position parameters - put a pointer on the graphic form just constructed - jump on to PR ALL. _0B38_PO_GR_1 (formally a free-standing subroutine, but only called from PO ANY; it constructs any of the "graphic forms", character codes 80h/128d to 8Fh/143d. These are not stored as "character forms", like the alphanumeric characters, since it is relatively easy to "draw" them whenever they are required. All the forms consist of a byte repeated four times to make the upper half of the form and then another byte repeated four times to form the lower half: each of these bytes is alwayseither 00h, 0Fh, F0h or FFh. The 10h/16d forms can be tabulated as follows: the upperline shows the last four bits of the character code, the lower shows the byte used in the_lower half of the character followed by the byte used in the upper half: 0000 0001 0010 0011 0100 0101 0110 0111 0000 000F 00F0 00FF 0F00 0F0F 0FF0 0FFF 1000 1001 1010 1011 1100 1101 1110 1111 F000 F00F F0F0 F0FF FF00 FF0F FFF0 FFFF The correspondence is obvious): - put a pointer on 5C92 MEMBOT; the calculator memory area of 30d bytes - call PO GR 2 and immediately exit into it; thus going through it twice and then returning into PO ANY. _0B3E_PO_GR_2 (formally a subroutine, but never called except at this point): rotate the character code right into the carry flag; on the first run this sets carry for odd character codes, which have F as last digit of their lo byte, see the table above. On the second run the character code has already been shifted twice, so carry is set by what started out as bit 2, and codes with bit 2 set have F as last digit of their hi byte - take the code from itself with the carry; making 00 for even codes or FF for odd, depending on the carry - AND the result with 0F; making 00 for even, 0F for odd, the lo nibble of the byte - rotate and subtract the character code again - AND this time with F0; making 00 for even, F0 for odd,the hi nibble of the byte - OR the two nibbles together to make the whole byte. - make a counter 04; the byte is used four times. _0B4C_PO_GR_3: put the byte just formed into the next location of the memory area - move on the pointer - reduce the counter - if it is not zero loop back to PO GR 3 - (four bytes loaded) return; the first time the routineis called, PO GR 2 is immediately entered again with the lo byteof the character code already shifted four bytes right, producing the byte for the lower half of the graphics character.The second time, this is a return into PO ANY. _0B52_PO_T&UDG (entered from PO ANY if the code is a token or user-defined graphic): subtract A5h/165d from the code - if this does not give carry jump on to PO T; the code is 165d or more, a token - (a user-defined graphic) add back 15h/21d; now the code is zero -> 14h/20d; 0Fh in the notes is incorrect - put a pointer on the address in 5C7B UDG; this is the base address for the UD graphics - jump on to PO CHAR 2 to print the character. _0B5F_PO_T (tokens): call 0C10 PO TOKENS to print out thetoken - jump back to PO FETCH to exit; the display address in HL has been overwritten. _0B65_PO_CHAR (output a single character code from the standard set; this entry point is also called as a subroutine from PO RIGHT, to move the cursor right by printing an "invisible space"): get the "base address of the character set" from 5C36 CHARS; this base is 100h/256d bytes before the start of the character set, so code 20h/32d lands on the first byte ofthe set, which is also the first byte of the form for 20h "space", and other codes correspondingly _0B6A_PO_CHAR_2: zero bit zero of FLAGS; "print the next token with a leading space" - if the present code is not space jump on to PO CHAR 3 - (it is space) set bit zero of FLAGS; no leading space after a space. _0B76_PO_CHAR_3: add eight times the character code to the base address; this finds the character form either in the standard set, if entry was from PO CHAR, or in the UDGs if it was from PO T&UDG. _0B7F_PR_ALL (DE holds a pointer to the first of the eight bytes of a character form, whether normal or a user- defined graphic or the ad hoc keyboard graphic constructed in the memory area; BC holds the print position, HL the display area address for the first byte): decrement the print position column number - prepare a new column number 21h/33d - if it didn't reach zero, jump on to PR ALL 1 - (end of the output line) decrement the line number - put 21h/33d as the column number - if bit 1 of FLAGS is zero jump on to PR ALL 1; output to the screen - (ZX printing) call 0ECD COPY BUFF to output the whole print buffer. _0B93_PR_ALL_1: check if the column number has been changed to 21h/33d - if it has call 0C55 PO SCR to check whether scrolling is required; line end - get the byte from 5C91 P FLAG - prepare an OVER mask 11111111b/FFh for OVER on - if bit zero of P FLAG is set jump on to PR ALL 2; it signals OVER on - change the OVER mask to 00000000b; OVER off. _0BA4_PR_ALL_2: rotate the P FLAG byte right twice - subtract it from itself with the carry; this makes an INVERSE mask, also 00000000b for "off" and 11111111b for "on", since bit 2 of P FLAG went into the carry - make a counter 08 for the eight bytes of the characterform - if bit 1 of FLAGS is zero jump on to PR ALL 3 with NC;output to the screen - (ZX printing) set bit 1 of FLAGS2; "print buffer not empty" - set the carry; it signals output to the ZX printer. _0BB6_PR_ALL_3 and_0BB7_PR_ALL_4: save the carry flag - get a pixel byte from the screen pointer - AND it with the OVER mask; this zeroes it for OVER offand leaves it unchanged for OVER on - XOR the result with the byte from the character form; this reverses each bit from the screen pixel which corresponds to a one in the character form, so for OVER off it just copies the character form - XOR the result with the INVERSE mask; this leaves it unchanged for INVERSE off and flops each bit for INVERSE on. For a complex example, suppose both INVERSE and OVER areon, the character on screen is upper-case letter O: ........ ..****.. .*....*. .*....*. .*....*. .*....*. ..****.. ........ and the character to be printed is X: ........ .*....*. ..*..*.. ...**... ...**... ..*..*.. .*....*. ........ The O is unchanged by the OVER mask, so when it is XORedwith the X we get: ........ .******. .**..**. .* **.*. .*.**.*. .**..**. .******. ........ The INVERSE mask XORs this to ******** *......* *..**..* *.*..*.* *.*..*.* *..**..* *......* ******** Try CLS: PRINT "OOOOO"; AT 0,0; INVERSE 1; OVER 1;"XXXXX" to see the effect of this on screen - if the saved flag signals ZX printing jump on to PR ALL 6 - (not ZX printing) increment the screen pointer by 100h/256d to find the next display position; see DISPLAY AREA. _0BC1_PR_ALL_5 (PR ALL 6 jumps back to here in ZX printing): increment the character form pointer - decrement the byte counter - if it is not down to zero yet loop back to PR ALL 4 for the next pixel byte - (all eight bytes output) put a pointer back on the last display area address loaded - read bit 1 of FLAGS; "ZX printer" flag [unnecessarily;INC and DEC do not affect carry, so the carry flag still signals"ZX printer" or not from the last time it was checked] - if it is zero for output to screen, call 0BDB PO ATTR to find the corresponding attribute address and put in the attribute from 5C8F ATTR T - decrement the print position column number; this is why it was put at 21h/33d for a new line start, rather than one - increment the display area address - return. _0BD3_PR_ALL_6 (ZX printing; in this case the destinationpointer is in the print buffer, not the display area): move on the pointer by 20h; to the next pixel byte in the print buffer - jump back into PR ALL 5. Exit: - RETs from PO RIGHT (incorrect), PO SPACE, PO STORE, POST E, PO ST PR - into 0DD9 CL SET, which exits back to PO STORE and RETs from there, from PO BACK 3, PO ENTER, PO AT SET - into 226C CO CHANGE, which makes a final adjustment tothe attribute svs, from CO TEMP 6, CO TEMP B and CO TEMP E - into 0C55 PO SCR, to check if scrolling is required, from PO AT ERR - the RETs from PO FETCH, except when it is made the exit routine by PO T, PO F PR, PO GR 3 and PR ALL 5 are "internal", as these routines are only called in the PRINT OUT routine - the RET from PO CHANGE, which is also an exit from PO TV 2 and PO TV 1, is "internal" in the call from PO CONT, and really also elsewhere, since the output routine is immediately called again with the changed address. Output parameters: none. Called from: 115E ED SPACES 18C1 OUT FLASH Rems: Introduction rather slow output routine 0D94 CL CHAN address put in output of channel 0DAF CL ALL address put in output of channel 15AF initial channel information 21E1 CO TEMP 1 misprint for 0010 PRINT A 1 21FC CO TEMP 4 misprint for 0010 PRINT A 1 2211 CO TEMP 5 (correct) called by PRINT OUT print position see DISPLAY AREA PRINT POSITION SUBROUTINE, print statement see 1FCD PRINT PRINT THE CURSOR SUBROUTINE see 18E1 OUT CURS PRINT 1 1FCF (1FCD PRINT) Exit from: 1FC9 LPRINT 1FCD PRINT PRINT 2 subroutine 1FDF See 1FCD PRINT. Called from: 1FCF PRINT 1 20C1 IN ITEM 1 PRINT 3 1FE5 (1FCD PRINT) Jumps from: auto (twice) PRINT 4 1FF2 (1FCD PRINT) Exit from: 1FDF PRINT 2 priorities see 24FB SCANNING PR ITEM 1 subroutine 1FFC See 1FCD PRINT. Called from: 1FE5 PRINT 3 21AF IN NEXT 1 PR ITEM 2 200E (1FCD PRINT) Jumps from: 1FFC PR ITEM 1 PR ITEM 3 2024 (1FCD PRINT) Exit from: 200E PR ITEM 2 Procrustean lengthening/shortening see 2B72 L DELETE$ (2AFF LET)