; PRINT3.src ; ; SPECTRUM PRINTOUT ROUTINE ; USES WORKSPACE POINTED TO BY IY ; 17/02/1986 J.G.HARSTON ; 18/06/2012 Comments added from original paper version ; Coding style and layout is rather... um... untidy ; PART TWO ; PRINTING CHARACTERS ; CLS, SCROLL, DEFWIN, DEFCHR POTOKEN EQU #0C10 PO_FETCH CALL PO_F_1 ; Get POSN and DFCC INC B ; Change POSN to 1 to max+1 INC C RET PO_F_1 LD HL,(DFCC) ; Display File Current Character LD BC,(POSN) ; Character X,Y position RET CL_SET DEC B ; Return POSN to 0 to max DEC C CL_S_1 CALL CL_ADDR ; Calculate DFCC from POSN LD (DFCC),HL LD (POSN),BC RET ; Print a character PO_ABLE BIT 3,(IY-PFLAG) JR Z,PO_NOT CP 165 JR C,PO_NOT SUB 165 JP POTOKEN PO_NOT CALL PO_ANY ; Print character CALL PO_FETCH ; Get POSN JP RIGHT ; Move cursor right PO_ANY CALL CHSCRL ; Check for any pending scroll BIT 4,(IY-MODE) JR Z,PO_A2 ; Not teletext CP 35 ; Convert teletext chars JR Z,PO_HASH ; '#' stored as #5F CP 95 JR Z,PO_LINE ; '`' stored as #23 CP 96 JR NZ,PO_REST ; '_' stored as #60 SUB 121 PO_HASH ADD A,59 PO_LINE INC A PO_REST LD (HL),A ; Store char BIT 5,(IY-MODE) RET Z ; Not double height LD DE,40 ADD HL,DE ; Step to next line LD (HL),A ; Store next line down RET PO_A2 CALL VDUVEC ; Check for VDU_V BIT 7,(IY-MODE) JP NZ,PO_THIN ; b7=Thin chars LD BC,(CHARS) ; Get address of characters CP 128 JR C,PO_CHAR ; Jump with 32-127 LD BC,(UDC) ; Get address of UDCs CP 160 JR NC,PO_UDC ; Jump with 160-255 CALL PO_A3 ; Build a block graphic JR PO_ALL2 ; Print chars 128-159 ; Build a block graphics character PO_A3 PUSH AF AND 239 CALL PO_GR1 POP AF CP 144 JR C,PO_GRA LD A,85 LD B,8 PO_GRL DEC HL PUSH AF OR (HL) LD (HL),A POP AF CPL DJNZ PO_GRL PO_GRA LD DE,GRMEM RET PO_GR1 LD HL,GRMEM LD B,A CALL PO_GR2 PO_GR2 RR B SBC A,A AND 15 LD C,A RR B SBC A,A AND 240 OR C BIT 7,(IY-MODE) JR Z,PO_GR3 RRCA RRCA PO_GR3 LD C,4 PO_GR4 LD (HL),A INC HL DEC C JR NZ,PO_GR4 RET PO_UDC SUB 160 PO_CHAR LD H,0 LD L,A ADD HL,HL ADD HL,HL ADD HL,HL ADD HL,BC EX DE,HL PO_ALL2 LD HL,(DFCC) ; HL=dest, DE=char matrix PUSH HL ; Save screen address LD A,8 ; 8 pixel lines SC_LOOP EX AF,AF' ; Save loop counter LD A,(DE) ; Get byte from char BIT 6,(IY-MODE) JR NZ,DWIDTH ; Double width CALL PIXLINE ; Do one/two pixel lines JR SC_CNT ; Jump to continue loop DWIDTH LD C,A ; Save byte in C CALL XPND ; Expand byte in C PUSH HL ; Save screen address CALL PIXLINE ; Store first byte EX (SP),HL ; Get screen address back INC HL ; Move right CALL XPND ; Expand byte in C again CALL PIXLINE ; Store pixel line POP HL ; Get orginal screen address back SC_CNT INC DE ; Net character byte INC H ; Next screen line EX AF,AF' DEC A ; Dec. loop count JR NZ,SC_LOOP ; Loop for 8 pixel lines POP HL ; Get screen address back JP PO_ATTR ; Store attribute PIXLINE LD B,A ; Save byte to store CALL ONEPIX ; Write to screen BIT 5,(IY-MODE) RET Z ; Not double height DHIGHT LD A,B INC H ; Do another pixel line CALL ONEPIX ; Write to screen EX AF,AF' ; Check loop counter CP 5 ; About to step over character line? JR Z,DH_INC ; Yes, need to adjust HL EX AF,AF' ; Restore loop counter RET DH_INC EX AF,AF' ; Restore loop counter LD A,H ; Step past character line to next SUB 7 LD H,A LD A,L ADD A,#20 LD L,A AND #E0 JR NZ,DH_2 LD A,H ADD A,8 ; Step over screen thirds LD H,A DH_2 DEC H RET ; Store one pixel line ONEPIX BIT 2,(IY-PFLAG) ; INVERSE JR Z,SET_1 CPL SET_1 BIT 0,(IY-PFLAG) ; OVER 1 - XOR JR Z,SET_2 XOR (HL) SET_2 BIT 1,(IY-PFLAG) ; OVER 2 - OR JR Z,SET_3 OR (HL) SET_3 LD (HL),A ; Store in screen RET ; Make double width XPND LD B,4 ; Expand 4 bits XOR A ; Start with zero X_LOOP BIT 7,C ; Check top bit of C JR Z,X_2 OR #C0 ; Set two bits in A X_2 RLCA ; Move two bits around in A RLCA RLC C ; And move one bit in C DJNZ X_LOOP ; Loop for 4 bits RET PO_ATTR CALL PR_ATTR ; Store attribute BIT 6,(IY-MODE) JR Z,PO_AT2 ; Not double width INC HL ; Move right CALL SET_ATTR ; Store attribute here as well DEC HL ; Move back left PO_AT2 BIT 5,(IY-MODE) RET Z ; Not double height LD DE,32 ADD HL,DE ; Step down one line CALL SET_ATTR ; Store attribute here BIT 6,(IY-MODE) RET Z ; Not double width INC HL ; Move right for last attribute JR SET_ATTR PR_ATTR CALL CL_ATTR ; Calculate attr address SET_ATTR LD DE,(WORKIY-ATTR) ; E=ATTR, D=MASK LD A,(HL) XOR E AND D XOR E BIT 6,(IY-PFLAG) JR Z,PO_AT3 AND 199 BIT 2,A JR NZ,PO_AT3 XOR 56 PO_AT3 BIT 4,(IY-PFLAG) JR Z,PO_AT4 AND 248 BIT 5,A JR NZ,PO_AT4 XOR 7 PO_AT4 LD (HL),A LD B,A RET ; Do thin chars PO_THIN RES 0,(IY-FLAGS) ; Char b0 RES 1,(IY-FLAGS) ; X posn b0 AND 127 CP 32 JR NC,TC_2 OR 128 CALL PO_A3 JR TC_4 TC_2 SRL A JR NC,TC_3 SET 0,(IY-FLAGS) ; Char b0 TC_3 LD DE,(TCHARS) LD H,0 LD L,A ADD HL,HL ADD HL,HL ADD HL,HL ADD HL,DE EX DE,HL TC_4 LD A,(IY-POSN_X) ADD A,(IY-WIND_X) LD B,#0F SRL A JR NC,TC_5 LD B,#F0 SET 1,(IY-FLAGS) ; Posn b0 TC_5 LD HL,(DFCC) LD A,8 TC_LOOP EX AF,AF' LD A,(DE) BIT 0,(IY-FLAGS) JR NZ,TC_6 SRL A SRL A SRL A SRL A TC_6 AND #0F BIT 1,(IY-FLAGS) JR NZ,TC_7 SLA A SLA A SLA A SLA A TC_7 LD C,A LD A,(HL) BIT 1,(IY-PFLAG) JR NZ,TC_8A BIT 0,(IY-PFLAG) JR Z,TC_8 XOR C JR TC_9 TC_8 AND B TC_8A OR C TC_9 LD (HL),A INC H INC DE EX AF,AF' DEC A JR NZ,TC_LOOP DEC H JP PR_ATTR CL_ATTR LD A,H RRCA RRCA RRCA AND 3 OR #58 LD H,A RET ; Convert logical posn in BC to absolute posn POABS2 LD A,(IY-WIND_X) ADD A,C LD C,A ; C=X+left LD A,(IY-WIND_Y) ADD A,B LD B,A ; B=Y+top RET ; Convert logical posn in BC to absolute posn PO_ABS CALL POABS2 ; Convert absolute posn in BC to physical position CHR_POSN BIT 7,(IY-MODE) JR Z,ABS_1 ; Not thin SRL C ; C=C / 2 RET ABS_1 BIT 6,(IY-MODE) JR Z,ABS_2 ; Not double width SLA C ; X=X * 2 ABS_2 BIT 5,(IY-MODE) JR Z,ABS_3 ; Not double height SLA B ; Y=Y * 2 ABS_3 BIT 4,(IY-MODE) RET Z ; Not teletext BIT 5,(IY-MODE) RET Z ; Not double-height teletext INC C ; X=X + 1, step past CHR$141 RET ; Scroll SCRL_D LD BC,0 CALL CL_ADDR ; Find addr of (0,0) CALL GET_SIZE ; Get physical size of window BIT 5,(IY-MODE) ; Double height? JR Z,SCRL_1 ; If double height, subtract for DEC B ; the extra bottom line SCRL_1 BIT 4,(IY-MODE) JP NZ,SCR_TT LD A,10 CALL VDUVEC ; Try VDU_V JR SCR_GO ; Check for only one line SCL_LO PUSH HL CALL SC_LINE ; Scroll current line POP HL CALL ADD_HL ; Step to next line SCR_GO DJNZ SCL_LO ; Loop for all lines DEC C ; Now clear last line INC B ; B=1 for one line BIT 5,(IY-MODE) JR Z,CL_LOOP ; Single height INC B ; Two lines to clear JR CL_LOOP ; CLS CL_SCR CALL HOME ; Set X,Y, COORDS and DFCC to (0,0) CALL GET_SIZE ; Get physical size of window DEC C ; First byte cleared at start BIT 4,(IY-MODE) JP NZ,CLS_TT ; Clear teletext screen LD A,12 CALL VDUVEC ; Check for VDU_V CL_LOOP PUSH HL CALL CL_LINE ; Clear current line POP HL CALL ADD_HL ; Step to next line DJNZ CL_LOOP ; Loop for all lines RET CL_LINE EX AF,AF' AND A ; Cy=0 for clear EX AF,AF' LD D,H LD E,L INC DE PUSH HL JR LINE_GO SC_LINE EX AF,AF' SCF ; Cy=1 for scroll EX AF,AF' PUSH HL CALL ADD_HL ; HL=next line BIT 5,(IY-MODE) CALL NZ,ADD_HL ; Two lines down for double height POP DE ; DE=this line LINE_GO LD A,8 ; 8 pixel lines L_LOOP PUSH HL PUSH DE EX AF,AF' JR C,L_2 LD (HL),0 L_2 EX AF,AF' CALL DO_LINE POP DE POP HL INC H ; Step to next pixel line INC D ; Step to next pixel line DEC A JR NZ,L_LOOP EX AF,AF' JR C,SC_ATTR ; Scroll attrs as well POP HL CALL CL_ATTR ; Get attr address LD A,(IY-ATTR) LD D,H LD E,L LD (HL),A INC DE DO_LINE DEC C INC C RET Z ; Nothing to do PUSH BC LD B,0 LDIR POP BC RET SC_ATTR DEC H DEC D CALL CL_ATTR EX DE,HL CALL CL_ATTR EX DE,HL JR DO_LINE GET_SIZE LD C,(IY-WIND_W) LD B,(IY-WIND_H) CALL CHR_POSN ; Convert logical to physical RET ADD_HL LD A,L ADD A,32 LD L,A BIT 0,L RET NC LD A,H ADD A,8 LD H,A RET CLS_TT PUSH HL LD (HL),32 LD D,H LD E,L INC DE CALL DO_LINE POP HL LD DE,40 ADD HL,DE DJNZ CLS_TT RET SCR_TT LD DE,40 EX DE,HL ADD HL,DE PUSH HL CALL DO_LINE POP HL DJNZ SCR_TT LD (HL),32 LD D,H LD E,L INC DE DEC C RET Z LDIR RET CL_ADDR PUSH BC ; Save POSN CALL PO_ABS ; Convert POSN to absolute position BIT 4,(IY-MODE) JR NZ,ADD_TT ; Convert teletext position XOR A ;; CALL VDUVEC ; Try VDU_V - will crash as BC on stack LD A,B RRCA RRCA RRCA AND #E0 OR C LD L,A ; L=X+(Y/32) LD A,B AND #18 OR #40 LD H,A ; H=#40+(Y MOD 32) POP BC ; Restore POSN RET ADD_TT LD HL,16384 LD DE,40 LD A,B ADD_LO AND A JR Z,ADD_END ADD HL,DE ; HL=#4000+40*Y DEC A JR ADD_LO ADD_END LD E,C ADD HL,DE ; HL=#4000+40*Y+X POP BC RET ; Define Window ; CHR$ 30; ; QBASE+3=left -> left QBASE+3 ; QBASE+2=bottom -> top QBASE+2 ; H=right -> width QBASE+1 ; D=top -> height QBASE+0 ; DEFWIND LD A,(QBASE+2) SUB D INC A ; (bottom-top)=height LD (QBASE+0),A ; height LD A,(QBASE+3) SUB H NEG INC A ; 1-(left-right)=width LD (QBASE+1),A ; width LD A,D LD (QBASE+2),A ; top LD A,30 CALL VDUVEC LD BC,#2119 ; Max soft screen BIT 4,(IY-MODE) JR Z,DW_GRAF LD BC,#291A ; Max teletext screen BIT 5,(IY-MODE) JR Z,DW_5 ; Not double height DEC B ; 39 columns JR DW_4 DW_GRAF BIT 7,(IY-MODE) JR Z,DW_2 ; Not thin chars LD B,#41 ; 64 columns JR DW_5 DW_2 BIT 6,(IY-MODE) JR Z,DW_3 ; Not double width LD B,#11 ; 16 columns DW_3 BIT 5,(IY-MODE) JR Z,DW_5 ; Not double height DW_4 LD C,#0D ; 12 rows DW_5 LD DE,(QBASE+0) LD HL,(QBASE+2) ; B=max cols, C=max rows ; D=width, E=height ; H=left, L=top LD A,H CP B RET NC ; left>cols ADD A,D CP B RET NC ; left+width>cols LD A,L CP C RET NC ; top>rows ADD A,E CP C RET NC ; top+height>row ; New window size fits into screen LD BC,(POSN) ; Get existing text posn CALL POABS2 ; Convert to absolute position LD (IY-WIND_X),H LD (IY-WIND_Y),L LD (IY-WIND_W),D LD (IY-WIND_H),E LD A,C ; Absolute X CP H JR C,DW_HOME ; Xleft+width LD A,B ; Absolute Y CP L JR C,DW_HOME ; Ytop+height LD A,C ; Convert to relative posn SUB H LD C,A LD A,B SUB L LD B,A DW_7 LD (POSN),BC JP CL_S_1 DW_HOME LD BC,0 JR DW_7 ; Define character ; CHR$ 31; ; char QBASE+8 ; pixelin1 QBASE+7 ; pixelin2 QBASE+6 ; pixelin3 QBASE+5 ; pixelin4 QBASE+4 ; pixelin5 QBASE+3 ; pixelin6 QBASE+2 ; pixline7 QBASE+1 ; pixline8 QBASE+0 ; DEFCHAR LD A,D LD (QBASE+0),A LD A,(QBASE+8) ; character CP 32 JR C,DCTRL ; 0-31 CP 128 JR C,DCHAR ; 32-127 CP 160 JR C,DGRAF ; 128-159 LD BC,(UDC) SUB 160 JR DC_1 DCHAR LD BC,(CHARS) DC_1 LD H,0 LD L,A ADD HL,HL ADD HL,HL ADD HL,HL ADD HL,BC ; HL=>character LD B,8 LD DE,QBASE+7 ; DE=>pixline1 DC_LP LD A,(DE) ; Copy definition LD (HL),A INC HL DEC DE DJNZ DC_LP RET DCTRL DGRAF LD A,31 ; Drop into VDUVEC VDUVEC BIT 2,(IY-FLAGS) RET Z ; Don't use VDU_V POP HL ; Drop return addr LD HL,(VDU_V) JMPVEC INC H DEC H JR NZ,JMPVC2 INC L DEC L RET Z ; VDU_V is zero JMPVC2 JP (HL) SET_ULA RET SET_SAA RET OSWORD RET THINSET DEFB #04, #04, #04, #04, #04, #00, #04, #00 DEFB #A0, #A6, #AF, #06, #06, #0F, #06, #00 DEFB #49, #69, #82, #42, #24, #C5, #49, #00 DEFB #42, #A2, #44, #C0, #B0, #A0, #50, #00 DEFB #24, #42, #42, #42, #42, #42, #24, #00 DEFB #00, #A4, #44, #EE, #44, #A4, #00, #00 DEFB #00, #00, #00, #0E, #00, #20, #20, #40 DEFB #00, #02, #02, #04, #04, #08, #48, #00 DEFB #64, #AC, #A4, #E4, #A4, #A4, #CE, #00 DEFB #44, #AA, #22, #44, #42, #8A, #E4, #00 DEFB #2E, #68, #68, #AC, #E2, #2A, #24, #00 DEFB #4E, #A2, #82, #C4, #A4, #A8, #48, #00 DEFB #44, #AA, #AA, #46, #A2, #AA, #44, #00 DEFB #00, #00, #42, #00, #00, #02, #42, #04 DEFB #00, #20, #4E, #80, #40, #2E, #00, #00 DEFB #04, #8A, #42, #24, #44, #80, #04, #00 DEFB #44, #AA, #AA, #EA, #EE, #8A, #6A, #00 DEFB #C4, #AA, #A8, #C8, #A8, #AA, #C4, #00 DEFB #CE, #A8, #A8, #AC, #A8, #A8, #CE, #00 DEFB #E4, #8A, #88, #C8, #8A, #8A, #86, #00 DEFB #AE, #A4, #A4, #E4, #A4, #A4, #AE, #00 DEFB #EA, #4A, #4A, #4C, #4A, #4A, #8A, #00 DEFB #8A, #8E, #8E, #8A, #8A, #8A, #EA, #00 DEFB #C4, #AA, #AA, #AA, #AA, #AA, #A4, #00 DEFB #C4, #AA, #AA, #CA, #8E, #8C, #86, #00 DEFB #C4, #AA, #A8, #C4, #A2, #AA, #A4, #00 DEFB #EA, #4A, #4A, #4A, #4A, #4A, #44, #00 DEFB #AA, #AA, #AA, #AA, #AE, #4E, #4A, #00 DEFB #AA, #AA, #4A, #4A, #44, #A4, #A4, #00 DEFB #EE, #28, #28, #48, #48, #88, #EE, #00 DEFB #0E, #82, #82, #42, #42, #22, #2E, #00 DEFB #40, #A0, #00, #00, #00, #00, #00, #0F DEFB #20, #40, #4C, #E2, #46, #4A, #E6, #00 DEFB #80, #80, #C6, #A8, #A8, #A8, #C6, #00 DEFB #20, #20, #64, #AA, #AE, #A8, #66, #00 DEFB #20, #40, #46, #EA, #4A, #46, #42, #0C DEFB #80, #84, #C0, #A4, #A4, #A4, #A4, #00 DEFB #08, #28, #08, #2A, #2C, #2A, #AA, #40 DEFB #40, #40, #4A, #4E, #4E, #4A, #2A, #00 DEFB #00, #00, #C4, #AA, #AA, #AA, #A4, #00 DEFB #00, #00, #C6, #AA, #AA, #C6, #83, #82 DEFB #00, #00, #A6, #C8, #84, #82, #8C, #00 DEFB #00, #40, #EA, #4A, #4A, #4A, #26, #00 DEFB #00, #00, #AA, #AA, #AE, #4E, #4A, #00 DEFB #00, #00, #AA, #AA, #4A, #A6, #A2, #0C DEFB #02, #04, #E4, #28, #44, #84, #E2, #00 DEFB #48, #44, #44, #02, #44, #44, #48, #00 DEFB #56, #A9, #0B, #0D, #0D, #0B, #09, #06