ca65 V2.17 - Git 582aa41 Main file : COS.ca65 Current file: COS.ca65 000000r 1 ; 000000r 1 ; Acorn System COS 000000r 1 ; 000000r 1 ; Produced from an original ROM purchased in December 1981 and 000000r 1 ; disassembled during 1982, transferred to CA65 format in 2018. 000000r 1 ; Revisited in 2020, commenting added to and mistakes corrected. 000000r 1 ; 000000r 1 ; Chris Oddy 000000r 1 ; 000000r 1 .setcpu "6502" 000000r 1 .listbytes unlimited 000000r 1 ; 000000r 1 ; *** Zeropage Registers *** 000000r 1 ; 000000r 1 filead := $C9 ; filename address (2 bytes) 000000r 1 ; 000000r 1 ; Note: some registers are used for different purposes during load and save 000000r 1 ; Used during save 000000r 1 loadad := $CB ; file load address (2 bytes) 000000r 1 execad := $CD ; file execution address (2 bytes) 000000r 1 starad := $CF ; data start address (2 bytes) 000000r 1 endad := $D1 ; data end address + 1 (2 bytes) 000000r 1 sy1sta := $CB ; system 1 format file start address (2 bytes) 000000r 1 sy1end := $CD ; system 1 format file end address +1 (2 bytes) 000000r 1 blksiz := $CF ; block size (1 byte) 000000r 1 blkno := $D0 ; block number (2 bytes) 000000r 1 blkflg := $D2 ; block flags (bit 5 clear for 1st block, bit 6 clear if block has no data, bit 7 clear for last block) (1 byte) 000000r 1 starpt := $D3 ; start data pointer (2 bytes) 000000r 1 endpt := $D5 ; end data pointer (2 bytes) 000000r 1 ; Used during load 000000r 1 lflag := $CD ; load flag (bit 7 set if load address valid) (1 byte) 000000r 1 ldchk := $CE ; load checksum (1 byte) 000000r 1 stradr := $CF ; file (or data) start address (2 bytes) 000000r 1 endadr := $D1 ; file (or data) end address +1 (2 bytes) 000000r 1 ; System 1 format file header 000000r 1 fhstar := $D4 ; file header start address (2 bytes) 000000r 1 fhend := $D6 ; file header end address (2 bytes) 000000r 1 ; ; System 2 format block header 000000r 1 bhload := $D4 ; block header load address (2 bytes) 000000r 1 bhexec := $D6 ; block header execution address (2 bytes) 000000r 1 bhlen := $D8 ; block header block length (1 byte) 000000r 1 bhno := $D9 ; block header block number (2 bytes) 000000r 1 bhflag := $DB ; block header block flags (bit 5 clear for 1st block, bit 6 clear if block has no data, bit 7 clear for last block) (1 byte) 000000r 1 chksum := $DC ; checksum (1 byte) 000000r 1 chkflg := $DD ; check flags (bit 6 set if System 1 'unnamed' file, bit 7 set for FLOAD 'don't check blocks') (1 byte) 000000r 1 lineno := $DE ; screen current linenumber, 0 is bottom of screen (1 byte) 000000r 1 line := $DF ; start address of screen current line, top of screen is 0 (2 bytes) 000000r 1 cursor := $E1 ; cursor position on the screen current line, bit 7 is set if screen output is disabled (1 byte) (1 byte) 000000r 1 curadr := $E2 ; screen cursor address (2 bytes) 000000r 1 crtcad := $E4 ; MSB of screen cursor CRTC address (1 byte) 000000r 1 temp_y := $E5 ; temporary Y (1 byte) 000000r 1 pc := $E6 ; program counter (2 bytes) 000000r 1 mesage := $E8 ; message flag ($FF - no messages, 0 - messages enabled) (1 byte) 000000r 1 wait_y := $E9 ; temporary Y storage (1 byte) 000000r 1 temp_a := $EC ; temporary A storage (1 byte) 000000r 1 drive := $EA ; drive (1 byte) 000000r 1 temp_x := $EB ; temporary X storage (1 byte) 000000r 1 not_pr := $FE ; non-printing character (1 byte) 000000r 1 irqa := $FF ; storage for A on IRQ (1 byte) 000000r 1 ; 000000r 1 buffer := $0100 ; input buffer (64 bytes) 000000r 1 filnam := $0140 ; string buffer (64 bytes) 000000r 1 ; 000000r 1 ; *** RAM Workspace *** 000000r 1 ; 000000r 1 stack := $01FF ; top of processor stack ($0180 to $01FF) 000000r 1 ; 000000r 1 ; OS redirection vectors ($0200 to $021D) 000000r 1 ; 000000r 1 NMIVEC := $0200 ; vector to NMI service routine 000000r 1 BRKVEC := $0202 ; vector to BRK service routine 000000r 1 IRQVEC := $0204 ; vector to IRQ service routine 000000r 1 COMVEC := $0206 ; vector to COS Command Line Interpreter (OSCCLI) 000000r 1 WRCVEC := $0208 ; vector to OS WRite CHaracter (OSWRCH) 000000r 1 RDCVEC := $020A ; vector to OS REad CHaracter (OSRDCH 000000r 1 LODVEC := $020C ; vector to OS LOAD file (OSLOAD) 000000r 1 SAVVEC := $020E ; vector to OS SAVE file (OSSAVE) 000000r 1 RDRVEC := $0210 ; vector to OS ReaD ARguments (OSRDAR) 000000r 1 STRVEC := $0212 ; vector to OS SeT ARguments (OSSTAR) 000000r 1 BGTVEC := $0214 ; vector to OS Byte GET (OSBGET) 000000r 1 BPTVEC := $0216 ; vector to OS Byte PUT (OSBPUT) 000000r 1 FNDVEC := $0218 ; vector to OS FiND (open) file (OSFIND) 000000r 1 SHTVEC := $021A ; vector to OS SHUT file (OSSHUT) 000000r 1 ECOVEC := $021C ; vector to ECONET handler 000000r 1 ; 000000r 1 ; *** Hardware Addresses *** 000000r 1 ; 000000r 1 ; 6502 CPU Board 8154 PIA (IC2) / 6502A CPU Board 6522 VIA (IC7) Keyboard Interface 000000r 1 ; 000000r 1 ; Note COS will work with either the 6502 CPU 8154 or 6502A CPU 6522 keyboard interfaces however the cassette interface will only work via a 6502 8154 000000r 1 ; 000000r 1 port_a5 := $0E05 ; bit 5 of Port A (8154 only, NHITONE input)) 000000r 1 port_a := $0E20 ; 8154 Port A Data Register (cassette interface) 000000r 1 port_b := $0E21 ; 8154 Port B / 6522 Port A Data Register (keyboard) 000000r 1 ddr_a := $0E22 ; 8154 Port A Data Direction Register 000000r 1 ddr_b := $0E23 ; 8154 Port B Data Direction Register (not used) 000000r 1 ; 000000r 1 ; Versatile Interface Board (VIB) 6522 (IC7) Printer Interface 000000r 1 ; 000000r 1 dr_b := $0C00 ; Port B Data Register (not used) 000000r 1 dr_a := $0C01 ; Port A Data Register (printer port) 000000r 1 dd_b := $0C02 ; Port B Data Direction Register 000000r 1 dd_a := $0C03 ; Port A Data Direction Register 000000r 1 pcr := $0C0C ; Peripheral Control Register 000000r 1 ; 000000r 1 ; *** Assembler switch to select VDU *** 000000r 1 ; 000000r 1 ; The original COS was compatible with the 40x25 (Teletext) VDU and automatically detects if the 6845 CRTC 000000r 1 ; is an early MC6845 type or later MC6845*1 type or equivalent and configures the CRTC appropriately. 000000r 1 000000r 1 ; This source code has been modified to also incorporate the CRTC configuration for the 80x25 VDU. 000000r 1 ; There is a choice of two 80x25 VDU CRTC configurations: 000000r 1 ; The first '80A' uses the register values as detailed in the System 5 Manual, these work however I have produced a slightly 000000r 1 ; modified configuration '80B' which works better with some monitors and VGA/HDMI video converters. 000000r 1 ; It has a corrected Horizontal Sync Pulse Width closer to the PAL standard (4.7uS), a shorter Vertical Sync Pulse Width 000000r 1 ; (the same as the BBC Computer's Mode 3) and the screen is moved slightly to the right so that it matches the 40x24 (Teletext) VDU 000000r 1 ; avoiding the need to adjust monitors/video converters when switching computers. 000000r 1 ; 000000r 1 ; Register R2 'Horizontal Sync Position': original value $66, modified value $60 moves the screen right 000000r 1 ; Register R3 '(Horizontal) Sync Pulse Width': original value $62, modified value $28 Horizontal Sync Pulse Width 4uS, Vertical Sync Pulse Width 128uS 000000r 1 ; 000000r 1 ; As the code for only the 40x25 configurations or one of the 80x25 configurations will fit in the EPROM a 'switch' allows a version to be assembled to suit. 000000r 1 ; 000000r 1 ; choose from: 000000r 1 ;.define vdutyp 40 ; (COS40) 40x25 (Teletext) VDU configurations 000000r 1 .define vdutyp 80 ; (COS80A) selects 80x25 VDU "80A" original configuration 000000r 1 ;.define vdutyp 81 ; (COS80B) selects 80x25 VDU "80B" modified configuration 000000r 1 ; 000000r 1 .if vdutyp = 40 000000r 1 ; 000000r 1 ; 6845 40x25 (Teletext) VDU 000000r 1 ; 000000r 1 vdua := $0400 ; VDU RAM Page 0 000000r 1 vdub := $0500 ; VDU RAM Page 1 000000r 1 vduc := $0600 ; VDU RAM Page 2 000000r 1 vdud := $0700 ; VDU RAM Page 3 000000r 1 vduadd := $0800 ; 6845 Register Select 000000r 1 vdudat := $0801 ; 6845 Data Register 000000r 1 vduwid := $28 ; width of screen (40 characters) 000000r 1 .endif 000000r 1 ; 000000r 1 .if vdutyp = 80 .or vdutyp = 81 000000r 1 ; 000000r 1 ; 6845 80x25 VDU 000000r 1 ; 000000r 1 vdua := $1000 ; VDU RAM Page 0 000000r 1 vdub := $1100 ; VDU RAM Page 1 000000r 1 vduc := $1200 ; VDU RAM Page 2 000000r 1 vdud := $1300 ; VDU RAM Page 3 000000r 1 vdue := $1400 ; VDU RAM Page 4 000000r 1 vduf := $1500 ; VDU RAM Page 5 000000r 1 vdug := $1600 ; VDU RAM Page 6 000000r 1 vduh := $1700 ; VDU RAM Page 7 000000r 1 vduadd := $1840 ; 6845 Register Select 000000r 1 vdudat := $1841 ; 6845 Data Register 000000r 1 vduwid := $50 ; width of screen (80 characters) 000000r 1 .endif 000000r 1 ; 000000r 1 ; VDU Screen Parameters 000000r 1 ; 000000r 1 nlines := $18 ; 24 lines 000000r 1 ; 000000r 1 ; *** ROMs *** 000000r 1 ; 000000r 1 ; Extension ROM 000000r 1 EXTROM := $F000 ; Start address of COS extension ROM (if present)vdu 000000r 1 ; 000000r 1 ; BASIC ROM 000000r 1 BASIC := $C2B2 ; BASIC ROM Entry POint 000000r 1 ; 000000r 1 ; *** ASCII Control Codes *** 000000r 1 ; 000000r 1 SOH := $01 ; Start Of Header (Cursor Left) 000000r 1 STXX := $02 ; Start of TeXt (Start Printer) 000000r 1 ETX := $03 ; End of TeXt (End Printer) 000000r 1 ACK := $06 ; ACKnowledge (Start Screen) 000000r 1 BS := $08 ; BackSpace 000000r 1 HT := $09 ; Horizontal Tab 000000r 1 LF := $0A ; LineFeed 000000r 1 VT := $0B ; Vertical Tab 000000r 1 FF := $0C ; FormFeed 000000r 1 CR := $0D ; Carriage Return 000000r 1 DC1 := $11 ; Device Control 1 (Read Character) 000000r 1 DC3 := $13 ; Device Control 3 (Cursor Right) 000000r 1 NAK := $15 ; Negative AcKnowledge (End Screen) 000000r 1 ETB := $17 ; End of Transmission Block (Cursor Up) 000000r 1 CAN := $18 ; CANcel 000000r 1 SUB := $1A ; SUBstitute (Cursor Down) 000000r 1 RS := $1E ; Record Separator (Home Cursor) 000000r 1 SPACE := $20 ; Space Bar 000000r 1 DEL := $7F ; DELete 000000r 1 ; 000000r 1 .org $F800 ; start address of System COS ROM 00F800 1 ; 00F800 1 ; Output a String of Characters 00F800 1 68 OUTSTR: pla ; retrieve return PC (-1) LSB 00F801 1 85 E6 sta pc 00F803 1 68 pla 00F804 1 85 E7 sta pc+1 ; and MSB 00F806 1 A0 00 outnxt: ldy #$00 ; Y=0 00F808 1 A2 E6 ldx #pc ; point x at pc 00F80A 1 20 83 FA jsr INCCMP ; increment pointer 00F80D 1 B1 E6 lda (pc),y ; get character from string 00F80F 1 30 06 bmi eos ; end of string ? 00F811 1 20 F4 FF jsr OSWRCH ; output character 00F814 1 4C 06 F8 jmp outnxt ; next character 00F817 1 6C E6 00 eos: jmp (pc) ; continue execution after string 00F81A 1 00F81A 1 20 ED FF cancel: jsr OSCRLF ; start again 00F81D 1 00F81D 1 ; Get Command From Buffer 00F81D 1 A9 2A COMIN: lda #'*' ; display prompt 00F81F 1 20 F4 FF jsr OSWRCH 00F822 1 A2 FF buffin: ldx #$FF 00F824 1 E8 nxtchr: inx ; increment buffer pointer 00F825 1 E0 40 cpx #$40 ; buffer full ? (64 bytes) 00F827 1 B0 0B bcs bufful 00F829 1 20 E6 FF read: jsr OSECHO ; read character from input channel and echo 00F82C 1 C9 18 cmp #CAN ; cancel ? 00F82E 1 F0 EA beq cancel ; yes - start again 00F830 1 C9 7F cmp #DEL ; delete ? 00F832 1 D0 05 bne nodel ; no - branch 00F834 1 CA bufful: dex ; backup buffer pointer 00F835 1 10 F2 bpl read ; and read another character 00F837 1 30 E9 bmi buffin ; start of line - start again 00F839 1 9D 00 01 nodel: sta buffer,x ; put character in buffer 00F83C 1 C9 0D cmp #CR ; CR ? 00F83E 1 D0 E4 bne nxtchr ; no - read next character 00F840 1 60 rts ; yes - return 00F841 1 00F841 1 ; Output Header Addresses 00F841 1 A2 D4 OUT2AD: ldx #fhstar ; pointer to System 1 file header start address 00F843 1 ; or System 2 block header load address 00F843 1 20 46 F8 jsr OUTADR ; output first address, a space, then the second address 00F846 1 00F846 1 ; Output the Address at X+1, X 00F846 1 B5 01 OUTADR: lda $01,x ; first byte 00F848 1 20 57 F8 jsr OUTBYT ; output the second byte (at X+1) 00F84B 1 E8 inx ; increment the pointer to the next address 00F84C 1 E8 inx 00F84D 1 B5 FE lda $FE,x ; output the first byte (now at X-2) 00F84F 1 20 57 F8 jsr OUTBYT 00F852 1 A9 20 outspc: lda #SPACE ; followed by a space 00F854 1 4C F4 FF jmp OSWRCH ; and return 00F857 1 00F857 1 ; Output the Byte in A In Hex 00F857 1 48 OUTBYT: pha ; save A 00F858 1 4A lsr a ; start with the upper nibble 00F859 1 4A lsr a ; shift to the lower nibble position 00F85A 1 4A lsr a 00F85B 1 4A lsr a 00F85C 1 20 60 F8 jsr OUTDIG ; and output 00F85F 1 68 pla ; retrieve A and output the lower nibble 00F860 1 00F860 1 ; Output the Hex Digit in A 00F860 1 29 0F OUTDIG: and #$0F ; mask off the upper nibble 00F862 1 C9 0A cmp #$0A ; is it A-F ? 00F864 1 90 02 bcc ascii ; no 00F866 1 69 06 adc #$06 ; yes - add offset to 'A' 00F868 1 69 30 ascii: adc #'0' ; convert to ASCII 00F86A 1 4C F4 FF jmp OSWRCH ; output character and return 00F86D 1 00F86D 1 ; Get Filename From Input Buffer 00F86D 1 20 CB F8 GTFLNM: jsr RDIBUF ; read next non-space character from input buffer 00F870 1 A2 00 ldx #$00 ; filename buffer pointer 00F872 1 C9 22 cmp #'"' ; is it a " ? 00F874 1 F0 06 beq quote ; yes 00F876 1 E8 inx ; increment filename buffer pointer 00F877 1 D0 1B bne unname ; no - must be a System 1 'unnamed file' (always branch) 00F879 1 4C F3 FA namerr: jmp synerr 00F87C 1 C8 quote: iny ; increment input buffer pointer 00F87D 1 B9 00 01 lda buffer,y ; read another character 00F880 1 C9 0D cmp #CR ; CR ? 00F882 1 F0 F5 beq namerr ; yes - syntax error 00F884 1 9D 40 01 sta filnam,x ; put character in filename buffer 00F887 1 E8 inx ; increment filename buffer pointer 00F888 1 C9 22 cmp #'"' ; was it a second " ? 00F88A 1 D0 F0 bne quote ; no keep reading buffer 00F88C 1 C8 iny ; yes - increment input buffer pointer 00F88D 1 B9 00 01 lda buffer,y ; check for further " 00F890 1 C9 22 cmp #'"' ; could be a " in filename 00F892 1 F0 E8 beq quote ; yes - represented by "", continue getting filename 00F894 1 A9 0D unname: lda #CR 00F896 1 9D 3F 01 sta filnam-1,x ; terminate filename with CR 00F899 1 A9 40 lda #filnam 00F89F 1 85 CA sta filead+1 00F8A1 1 A2 C9 ldx #filead ; point X at filename pointer 00F8A3 1 60 rts ; and return 00F8A4 1 00F8A4 1 ; Copy File Parameters and Check Filename Length 00F8A4 1 A0 00 CPYPAR: ldy #$00 ; source file parameters pointer 00F8A6 1 B5 00 move: lda $00,x ; read source file parameter 00F8A8 1 99 C9 00 sta filead,y ; copy to file parameter table 00F8AB 1 E8 inx ; increment source pointer 00F8AC 1 C8 iny ; increment destination pointer 00F8AD 1 C0 0A cpy #$0A ; have we copied all 10 bytes (5 addresses) ? 00F8AF 1 90 F5 bcc move ; no - continue 00F8B1 1 A0 FF ldy #$FF ; Y=-1 00F8B3 1 A9 0D lda #CR ; check the length of the filename 00F8B5 1 C8 notcr: iny 00F8B6 1 C0 11 cpy #$11 ; filename too long, >16 characters ? 00F8B8 1 D0 09 bne notend 00F8BA 1 20 00 F8 jsr OUTSTR 00F8BD 1 4E 61 6D 65 .byte "Name" ; output 'Name' error message 00F8C1 1 EA nop 00F8C2 1 00 brk ; and break 00F8C3 1 D1 C9 notend: cmp (filead),y ; compare next filename character with CR 00F8C5 1 D0 EE bne notcr ; if not CR go around again 00F8C7 1 C0 00 cpy #$00 ; CR - return with Y containing the length of the filename 00F8C9 1 60 rts ; and Z=1 if length is 0 00F8CA 1 00F8CA 1 C8 space: iny 00F8CB 1 ; Read the Yth Character From the Input Buffer 00F8CB 1 B9 00 01 RDIBUF: lda buffer,y 00F8CE 1 C9 20 cmp #SPACE ; ignoring spaces 00F8D0 1 F0 F8 beq space 00F8D2 1 60 rts ; and return 00F8D3 1 00F8D3 1 ; Test Key Value In A For Hex 00F8D3 1 C9 30 HEXKEY: cmp #'0' ; > '0' ? 00F8D5 1 90 10 bcc nothex ; return invalid hex 00F8D7 1 C9 3A cmp #':' ; < '9' ? 00F8D9 1 90 08 bcc hex ; yes - valid hex 00F8DB 1 E9 07 sbc #$07 ; convert 'A' to 'F' 00F8DD 1 90 08 bcc nothex ; if < 'A' then not hex 00F8DF 1 C9 40 cmp #'@' ; > 'F' ? 00F8E1 1 B0 03 bcs hexrtn ; return with C=1, invalid hex digit 00F8E3 1 29 0F hex: and #$0F ; valid hex digit, convert to ASCII 00F8E5 1 18 clc ; (unnecessarily set) C=0 00F8E6 1 60 hexrtn: rts ; and return, valid hex digit 00F8E7 1 38 nothex: sec ; C=1 00F8E8 1 60 rts ; and return, invalid hex digit 00F8E9 1 00F8E9 1 ; Get (up to) 4-digit Hex Parameter from Input Buffer and Store at X 00F8E9 1 A9 00 HXPARA: lda #$00 ; set parameter to 0 00F8EB 1 95 00 sta $00,x 00F8ED 1 95 01 sta $01,x 00F8EF 1 95 02 sta $02,x 00F8F1 1 20 CB F8 jsr RDIBUF ; ignore leading spaces 00F8F4 1 B9 00 01 rdnxch: lda buffer,y ; read character from input buffer 00F8F7 1 20 D3 F8 jsr HEXKEY ; is it hex ? 00F8FA 1 B0 15 bcs delim ; branch if not hex (delimiter character ?) 00F8FC 1 0A asl a ; shift up a digit 00F8FD 1 0A asl a 00F8FE 1 0A asl a 00F8FF 1 0A asl a 00F900 1 94 02 sty $02,x ; temporarily save the input buffer pointer 00F902 1 A0 04 ldy #$04 00F904 1 0A shfdig: asl a ; shift X, X+1 and A left one digit (4-bits) 00F905 1 36 00 rol $00,x 00F907 1 36 01 rol $01,x 00F909 1 88 dey 00F90A 1 D0 F8 bne shfdig 00F90C 1 B4 02 ldy $02,x ; retrieve the input buffer pointer 00F90E 1 C8 iny ; increment buffer pointer 00F90F 1 D0 E3 bne rdnxch ; always branch to read next character 00F911 1 B5 02 delim: lda $02,x ; set Z if no parameter found 00F913 1 60 rts ; and return 00F914 1 00F914 1 ; COS Command Table 00F914 1 42 41 53 49 COMTAB: .byte "BASIC",CR,>BASIC,CCAT,LOAD,SAVE,GO,RUN,MEM,MON,NOMON,DRIV,USE,FLOAD,COMERR,5 - 'record' 00FCF0 1 20 00 F8 jsr OUTSTR ; must be <5 - 'Play' 00FCF3 1 50 6C 61 79 .byte "Play" 00FCF7 1 D0 15 bne outdrv ; followed by 00FCF9 1 20 00 F8 record: jsr OUTSTR ; 'Record' 00FCFC 1 52 65 63 6F .byte "Record" 00FD00 1 72 64 00FD02 1 D0 0A bne outdrv 00FD04 1 20 00 F8 rewind: jsr OUTSTR ; followed by 00FD07 1 52 65 77 69 .byte "Rewind" ; 'Rewind' 00FD0B 1 6E 64 00FD0D 1 EA nop 00FD0E 1 20 00 F8 outdrv: jsr OUTSTR ; ' drive' 00FD11 1 20 64 72 69 .byte " drive " 00FD15 1 76 65 20 00FD18 1 A5 EA lda drive ; and output drive number 00FD1A 1 20 60 F8 jsr OUTDIG 00FD1D 1 20 E3 FF nomes: jsr OSRDCH ; wait for key press 00FD20 1 4C ED FF jmp OSCRLF ; output CR LF and return 00FD23 1 00FD23 1 ; Put Byte To Tape 00FD23 1 86 EB BPT: stx temp_x ; save X 00FD25 1 08 php ; save status register on stack 00FD26 1 A2 07 ldx #$07 ; bit counter 00FD28 1 8E 20 0E stx port_a ; turn low tone on 00FD2B 1 20 C1 FC jsr check ; add A to checksum 00FD2E 1 6A ror a ; backup 2 bits 00FD2F 1 6A ror a 00FD30 1 20 43 FD wrbit: jsr WTBIT ; wait a bit period 00FD33 1 6A ror a ; put bit in bit 6 position 00FD34 1 8D 20 0E sta port_a ; send it 00FD37 1 CA dex 00FD38 1 10 F6 bpl wrbit ; do all 8 bits 00FD3A 1 20 43 FD jsr WTBIT 00FD3D 1 8E 20 0E stx port_a ; turn high tone on 00FD40 1 28 plp ; retrieve X and status register 00FD41 1 00FD41 1 ; Retrieve X and Cassette Timing Wait 00FD41 1 A6 EB WTBITX: ldx temp_x ; retrieve X and 00FD43 1 00FD43 1 ; Cassette Timing Wait for a Bit Period (3.33mS) 00FD43 1 20 46 FD WTBIT: jsr wthalf ; do a half wait (1.66mS) and then do it again 00FD46 1 84 E9 wthalf: sty wait_y ; save Y 00FD48 1 78 sei ; disable interrupts 00FD49 1 A0 48 ldy #$48 ; 72 00FD4B 1 88 wait1: dey 00FD4C 1 D0 FD bne wait1 ; go round 72 times (72 x 5uS = 360uS) 00FD4E 1 88 wait2: dey 00FD4F 1 D0 FD bne wait2 ; go round 256 times (256 x 5uS = 1280uS) 00FD51 1 A4 E9 ldy wait_y ; retrieve Y 00FD53 1 60 rts ; and return 00FD54 1 00FD54 1 ; Read Character From Input Channel 00FD54 1 2C 21 0E RDC: bit port_b ; test keyboard strobe line 00FD57 1 10 FB bpl RDC ; wait for it to go high (key not pressed) 00FD59 1 AD 21 0E waitlo: lda port_b 00FD5C 1 30 FB bmi waitlo ; and then wait for it to low (key pressed) 00FD5E 1 C9 11 cmp #DC1 ; check for copy key (control Q) 00FD60 1 F0 25 beq KCOPY 00FD62 1 C9 17 cmp #ETB ; check for cursor keys - ETB End of Transmission (control W, cursor up) 00FD64 1 F0 0D beq keyup ; and convert to VT 00FD66 1 C9 01 cmp #SOH ; SOH Start Of Header (control A, cursor left) 00FD68 1 F0 0D beq keleft ; and convert to BS 00FD6A 1 C9 13 cmp #DC3 ; DC3 Device Control 3 (control S, cursor right) 00FD6C 1 F0 0D beq kright ; and convert to HT 00FD6E 1 C9 1A cmp #SUB ; SUB Substitute (control Z, cursor down) 00FD70 1 F0 0D beq kedown ; and convert to LF 00FD72 1 60 rts ; not copy or a cursor key - return 00FD73 1 ; convert keyboard cursor keys to VDU codes 00FD73 1 A9 0B keyup: lda #VT ; ETB becomes Vertical Tab 00FD75 1 D0 0A bne KCURSR ; and use the VDU handler to action 00FD77 1 A9 08 keleft: lda #BS ; SOH becomes BS BackSpace 00FD79 1 D0 06 bne KCURSR ; and use the VDU handler to action 00FD7B 1 A9 09 kright: lda #HT ; DC3 becomes HT Horizontal Tab 00FD7D 1 D0 02 bne KCURSR ; and use the VDU handler to action 00FD7F 1 A9 0A kedown: lda #LF ; HT becomes LF LineFeed 00FD81 1 00FD81 1 ; Handle the Cursor Key Codes 00FD81 1 20 9A FD KCURSR: jsr wrvdu ; use the VDU handler 00FD84 1 4C 54 FD jmp RDC ; and get another key 00FD87 1 00FD87 1 ; Handle the COPY Key Code 00FD87 1 84 E5 KCOPY: sty temp_y ; save Y 00FD89 1 08 php ; save status register on stack 00FD8A 1 A4 E1 ldy cursor ; horizontal cursor position 00FD8C 1 D8 cld ; make sure we're in binary mode 00FD8D 1 20 3F FE jsr CALC ; recalculate screen cursor addresses 00FD90 1 A0 00 ldy #$00 ; set cursor offset to 0 00FD92 1 B1 E2 lda (curadr),y ; get the character at the cursor position 00FD94 1 4C A3 FD jmp rtsyps ; and return 00FD97 1 00FD97 1 ; Write Character to Output Channel(s) 00FD97 1 20 A7 FD WRC: jsr PRINT ; call printer handler 00FD9A 1 08 wrvdu: php ; save status register on stack 00FD9B 1 48 pha ; save A on stack 00FD9C 1 D8 cld ; make sure we're in binary mode 00FD9D 1 84 E5 sty temp_y ; save Y 00FD9F 1 20 68 FE jsr VDU ; call the VDU handler 00FDA2 1 68 pla ; retrieve A from stack 00FDA3 1 A4 E5 rtsyps: ldy temp_y ; retrieve Y 00FDA5 1 28 plp ; retrieve status register from stack 00FDA6 1 60 rts ; and return 00FDA7 1 00FDA7 1 ; Printer Handler 00FDA7 1 48 PRINT: pha ; save A on stack 00FDA8 1 C9 02 cmp #STXX ; start printing ? 00FDAA 1 F0 29 beq pron ; yes - enable printing 00FDAC 1 C9 03 cmp #ETX ; end printing ? 00FDAE 1 F0 36 beq proff ; yes - disable printing 00FDB0 1 C5 FE cmp not_pr ; compare with character not to print 00FDB2 1 F0 07 beq noprnt ; match - nothing to do 00FDB4 1 AD 0C 0C lda pcr ; is printer enabled ? 00FDB7 1 29 0E and #$0E 00FDB9 1 D0 02 bne on ; yes - print 00FDBB 1 68 noprnt: pla ; no - retrieve A from stack 00FDBC 1 60 rts ; and return 00FDBD 1 68 on: pla ; yes - retrieve data byte 00FDBE 1 2C 01 0C prwait: bit dr_a ; wait for ready bit low 00FDC1 1 30 FB bmi prwait 00FDC3 1 8D 01 0C sta dr_a ; then output character 00FDC6 1 48 pha ; and save for return 00FDC7 1 AD 0C 0C lda pcr 00FDCA 1 29 F0 and #$F0 ; keep control bits 00FDCC 1 09 0C ora #$0C ; strobe line low 00FDCE 1 8D 0C 0C sta pcr ; write to printer port control register 00FDD1 1 09 02 ora #$02 ; strobe line high 00FDD3 1 D0 0C bne prrtn ; write to printer port control register and return (always branch) 00FDD5 1 A9 7F pron: lda #$7F ; enable printer 00FDD7 1 8D 03 0C sta dd_a ; set all pins of printer port as outputs except PA7 00FDDA 1 AD 0C 0C lda pcr ; write to printer port control register 00FDDD 1 29 F0 and #$F0 ; keep control bits 00FDDF 1 09 0E ora #$0E ; strobe line high 00FDE1 1 8D 0C 0C prrtn: sta pcr ; write to printer port control register 00FDE4 1 68 pla ; retrieve A from stack 00FDE5 1 60 rts ; and return 00FDE6 1 AD 0C 0C proff: lda pcr ; disable printer 00FDE9 1 29 F0 and #$F0 ; keep control bits 00FDEB 1 B0 F4 bcs prrtn ; and return 00FDED 1 68 tworts: pla ; remove return address 00FDEE 1 68 pla 00FDEF 1 60 rts ; and return to previous return address 00FDF0 1 00FDF0 1 ; Move the Cursor Left One Character 00FDF0 1 88 CURLFT: dey ; decrement horizontal cursor position 00FDF1 1 10 14 bpl uprtn ; is it past the start of the line ?, no -return 00FDF3 1 A0 4F ldy #vduwid-1 ; yes - set cursor position to end of line and 00FDF5 1 00FDF5 1 ; Move the Cursor Up One Line 00FDF5 1 A5 DE CURSUP: lda lineno ; screen current line number 00FDF7 1 C9 18 cmp #nlines ; top of screen ? 00FDF9 1 B0 F2 bcs tworts ; yes - return completely can't go any higher 00FDFB 1 E6 DE inc lineno ; move up one line 00FDFD 1 00FDFD 1 ; Subtract a Line from the Start Address of the Screen Current Line 00FDFD 1 A5 DF SUBLIN: lda line ; start address of screen current line 00FDFF 1 E9 4F sbc #vduwid-1 ; subtract width of a line 00FE01 1 85 DF sta line ; update 00FE03 1 B0 02 bcs uprtn ; if not carry finished 00FE05 1 C6 E0 dec line+1 ; otherwise decrement MSB of address 00FE07 1 60 uprtn: rts ; and return 00FE08 1 00FE08 1 C6 DE notbot: dec lineno ; not bottom just decrement line number 00FE0A 1 60 rts ; and return 00FE0B 1 00FE0B 1 ; Move the Cursor Down One Line 00FE0B 1 A0 50 CURDWN: ldy #vduwid ; move cursor to end of line 00FE0D 1 20 3F FE jsr CALC ; recalculate screen cursor addresses 00FE10 1 A5 E2 lda curadr ; read LSB of screen cursor address 00FE12 1 85 DF sta line ; update LSB of start address of screen current line 00FE14 1 A5 E4 lda crtcad ; read MSB of screen cursor CRTC address 00FE16 1 85 E0 sta line+1 ; update MSB of start address of screen current line 00FE18 1 A5 DE lda lineno ; check linenumber 00FE1A 1 D0 EC bne notbot ; bottom of screen ? 00FE1C 1 A0 0D ldy #$0D ; yes - scroll screen up 00FE1E 1 8C 40 18 sty vduadd ; select CRTC Display Start Address (Low) Register 00FE21 1 A5 DF lda line ; LSB of start address of screen current line 00FE23 1 38 sec 00FE24 1 ; subtract start address of start of bottom line 00FE24 1 ; 80x25 VDU - $03C0 00FE24 1 ; Teletext VDU - $0780 00FE24 1 .if vdutyp = 80 .or vdutyp = 81 00FE24 1 E9 80 sbc #$80 ; 80x25 VDU 00FE26 1 .else 00FE26 1 sbc #$C0 ; Teletext VDU 00FE26 1 .endif 00FE26 1 00FE26 1 8D 41 18 sta vdudat ; update CRTC register 00FE29 1 88 dey ; Y=$C 00FE2A 1 8C 40 18 sty vduadd ; select CRTC Display Start Address (High) Register 00FE2D 1 A5 E0 lda line+1 ; MSB of start address of screen current line 00FE2F 1 00FE2F 1 .if vdutyp = 80 .or vdutyp = 81 00FE2F 1 00FE2F 1 E9 07 sbc #$07 ; 80x25 VDU 00FE31 1 .else 00FE31 1 sbc #$03 ; Teletext VDU 00FE31 1 .endif 00FE31 1 00FE31 1 8D 41 18 sta vdudat ; update CRTC register 00FE34 1 A0 4F ldy #vduwid-1 00FE36 1 A9 20 lda #SPACE ; output a line of spaces to clear new bottom line 00FE38 1 20 54 FE newlin: jsr VDUCHR 00FE3B 1 88 dey 00FE3C 1 10 FA bpl newlin 00FE3E 1 60 rts ; and return 00FE3F 1 00FE3F 1 ; Calculate Screen Cursor Addresses 00FE3F 1 48 CALC: pha ; save A on stack 00FE40 1 18 clc ; clear carry 00FE41 1 98 tya ; Y is position of cursor on current line 00FE42 1 65 DF adc line ; add LSB of start address of screen current line 00FE44 1 85 E2 sta curadr ; save as LSB of screen cursor address 00FE46 1 A5 E0 lda line+1 ; read MSB of start address of screen current line 00FE48 1 69 00 adc #$00 ; add the carry 00FE4A 1 85 E4 sta crtcad ; and save as the MSB of the CRTC cursor address 00FE4C 1 29 07 and #$07 ; add offset to MSB to produce 'real' screen address 00FE4E 1 09 10 ora #>vdua ; either $04 for address in range $0400 to $07FF (Teletext VDU) 00FE50 1 ; or $10 for address in range $07FF to $1000 (80x25 VDU) 00FE50 1 85 E3 sta curadr+1 ; and save as the MSB of the 'real' cursor address 00FE52 1 68 pla ; retrieve A from stack 00FE53 1 60 rts ; and return 00FE54 1 00FE54 1 ; Output Character to VDU 00FE54 1 20 3F FE VDUCHR: jsr CALC ; recalculate screen cursor addresses 00FE57 1 84 E4 sty crtcad ; save Y (cursor) (crtcad is not being used) 00FE59 1 A0 00 ldy #$00 ; set cursor offset to 0 00FE5B 1 91 E2 sta (curadr),y ; output character to cursor address 00FE5D 1 A4 E4 ldy crtcad ; retrieve Y (cursor) 00FE5F 1 60 rts ; and return 00FE60 1 00FE60 1 ; Enable Screen Output 00FE60 1 18 VDUON: clc ; clear carry 00FE61 1 00FE61 1 ; Disable Screen Output (carry is set on entry) 00FE61 1 08 VDUOFF: php ; save status register on stack 00FE62 1 06 E1 asl cursor ; shift carry bit into MS bit of cursor 00FE64 1 28 plp ; without affecting other bits 00FE65 1 66 E1 ror cursor 00FE67 1 60 rts ; and return 00FE68 1 00FE68 1 ; VDU Handler 00FE68 1 C9 06 VDU: cmp #ACK ; start screen ? 00FE6A 1 F0 F4 beq VDUON ; enable screen output and return 00FE6C 1 C9 15 cmp #NAK ; end screen ? 00FE6E 1 F0 F1 beq VDUOFF ; disable screen output and return 00FE70 1 A4 E1 ldy cursor ; Y = cursor position on current line 00FE72 1 30 2D bmi vdurtn ; if bit 7 is set screen output is disabled, branch to return 00FE74 1 C9 20 cmp #SPACE ; is it a control character ? 00FE76 1 90 34 bcc VCTRL ; yes branch 00FE78 1 C9 7F cmp #DEL ; also check for delete 00FE7A 1 F0 26 beq VDUDEL ; and branch 00FE7C 1 20 54 FE char: jsr VDUCHR ; must be a displayable character - write to screen and 00FE7F 1 00FE7F 1 ; Handle the HT VDU Code (move cursor right) 00FE7F 1 C8 VDUHT: iny ; increment cursor horizontal position 00FE80 1 C0 50 cpy #vduwid ; end of line ? 00FE82 1 90 05 bcc cursr ; no - update cursor position 00FE84 1 20 0B FE jsr CURDWN ; yes - move cursor to the start of a new line and scroll if required 00FE87 1 00FE87 1 ; Handle the CR VDU Code (move cursor to start of current line) 00FE87 1 A0 00 VDUCR: ldy #$00 ; set cursor position to start of line 00FE89 1 20 3F FE cursr: jsr CALC ; recalculate screen cursor addresses 00FE8C 1 84 E1 sty cursor ; save cursor position 00FE8E 1 A0 0F ldy #$0F ; set new cursor position in CRT controller 00FE90 1 8C 40 18 sty vduadd ; select register F cursor low address 00FE93 1 A5 E2 lda curadr 00FE95 1 8D 41 18 sta vdudat ; write LSB of address 00FE98 1 88 dey 00FE99 1 8C 40 18 sty vduadd ; select register E cursor high address 00FE9C 1 A4 E4 ldy crtcad 00FE9E 1 8C 41 18 sty vdudat ; write MSB of address 00FEA1 1 60 vdurtn: rts ; and return 00FEA2 1 00FEA2 1 ; Handle the DEL VDU Code (cursor left and clear character) 00FEA2 1 20 F0 FD VDUDEL: jsr CURLFT ; move cursor left 00FEA5 1 A9 20 lda #SPACE ; and overwrite with a space 00FEA7 1 20 54 FE jsr VDUCHR 00FEAA 1 10 DD bpl cursr ; then update cursor position (always branch) 00FEAC 1 00FEAC 1 ; Handle VDU Control Codes 00FEAC 1 C9 0D VCTRL: cmp #CR ; CR Carriage Return ? 00FEAE 1 F0 D7 beq VDUCR ; yes - set cursor position to start of line 00FEB0 1 C9 0A cmp #LF ; LF LineFeed ? 00FEB2 1 F0 1C beq VDULF ; yes - move cursor down 00FEB4 1 C9 0C cmp #FF ; FF FormFeed ? 00FEB6 1 F0 37 beq VDUFF ; yes - clear screen and home cursor 00FEB8 1 C9 08 cmp #BS ; BS BackSpace ? 00FEBA 1 F0 0E beq VDUBS ; yes - move cursor left 00FEBC 1 C9 1E cmp #RS ; RS Record Separator ? 00FEBE 1 F0 18 beq VDURS ; yes - home cursor 00FEC0 1 C9 0B cmp #VT ; VT Vertical Tab ? 00FEC2 1 F0 25 beq VDUVT ; yes - move cursor up 00FEC4 1 C9 09 cmp #HT ; HT Horizontal Tab ? 00FEC6 1 D0 B4 bne char ; no - some other control key ? - try and output it 00FEC8 1 B0 B5 bcs VDUHT ; yes - move cursor right 00FECA 1 00FECA 1 ; Handle the BS VDU Code (move cursor left one character) 00FECA 1 20 F0 FD VDUBS: jsr CURLFT ; move cursor left 00FECD 1 4C 89 FE jmp cursr ; and update cursor position 00FED0 1 00FED0 1 ; Handle the LF VDU Code (move cursor down one line) 00FED0 1 20 0B FE VDULF: jsr CURDWN ; move cursor down 00FED3 1 A4 E1 ldy cursor ; horizontal position remains the same so retrieve it 00FED5 1 4C 89 FE jmp cursr ; and update cursor position 00FED8 1 00FED8 1 ; Handle the RS VDU Code (home cursor) 00FED8 1 A9 18 VDURS: lda #nlines ; number of lines on screen 00FEDA 1 A4 DE ldy lineno ; set to top line 00FEDC 1 85 DE sta lineno ; set top of screen 00FEDE 1 C0 18 movtop: cpy #nlines ; check cursor isn't already on top line ? 00FEE0 1 B0 A5 bcs VDUCR ; yes - check if start of line 00FEE2 1 C8 iny ; move up a line 00FEE3 1 20 FD FD jsr SUBLIN 00FEE6 1 4C DE FE jmp movtop ; keep going until at top of screen 00FEE9 1 00FEE9 1 ; Handle the VT VDU Code (move cursor up one line) 00FEE9 1 20 F5 FD VDUVT: jsr CURSUP ; move cursor up 00FEEC 1 4C 89 FE jmp cursr ; and update cursor position 00FEEF 1 00FEEF 1 ; Handle the FF VDU Code (clear screen) 00FEEF 1 A9 20 VDUFF: lda #SPACE ; fill VDU memory with spaces 00FEF1 1 A0 00 ldy #$00 00FEF3 1 00FEF3 1 .if vdutyp = 80 .or vdutyp = 81 ; 80x25 VDU 00FEF3 1 99 00 10 clrvdu: sta vdua,y ; fill screen memory blocks 00FEF6 1 99 00 11 sta vdub,y 00FEF9 1 99 00 12 sta vduc,y 00FEFC 1 99 00 13 sta vdud,y 00FEFF 1 99 00 14 sta vdue,y 00FF02 1 99 00 15 sta vduf,y 00FF05 1 99 00 16 sta vdug,y 00FF08 1 99 00 17 sta vduh,y 00FF0B 1 C8 iny 00FF0C 1 D0 E5 bne clrvdu ; do all 256 bytes of each block 00FF0E 1 00FF0E 1 .else ; Teletext VDU 00FF0E 1 clrvdu: sta vdua,y ; fill screen memory blocks 00FF0E 1 sta vdub,y 00FF0E 1 sta vduc,y 00FF0E 1 sta vdud,y 00FF0E 1 iny 00FF0E 1 bne clrvdu ; do all 256 bytes of each block 00FF0E 1 .endif 00FF0E 1 00FF0E 1 84 DF lodreg: sty line ; set LSB of screen address (Y=0) 00FF10 1 84 E1 sty cursor ; set VDU On and cursor to start of line 00FF12 1 86 DE stx lineno ; save X 00FF14 1 00FF14 1 .if vdutyp = 80 .or vdutyp = 81 ; 80x25 VDU 00FF14 1 A2 0D ldx #$0D ; point to end of VDU parameter table 00FF16 1 A0 0D ldy #$0D ; VDU register pointer 00FF18 1 EA nop ; packing 00FF19 1 EA nop 00FF1A 1 EA nop 00FF1B 1 .else ; 40x25 (Teletext) VDU 00FF1B 1 ; determine which CRTC is present 00FF1B 1 ldx #$0D ; point to end of VDU parameter table 00FF1B 1 lda #$AA ; test value 00FF1B 1 ldy #$0D ; VDU register pointer 00FF1B 1 sty vduadd ; by testing CRTC register R13 00FF1B 1 sta vdudat ; store $AA and read back 00FF1B 1 cmp vdudat 00FF1B 1 beq vdulod ; equal - must be an updated/enhanced type CRTC MC6845*1 or equivalent 00FF1B 1 ldx #$1B ; otherwise must be an original MC6845 type - offset to 2nd table 00FF1B 1 .endif 00FF1B 1 00FF1B 1 8C 40 18 vdulod: sty vduadd ; write CRTC register number (working backwards) 00FF1E 1 BD 7A FF lda VDUPAR,x ; load data from table 00FF21 1 8D 41 18 sta vdudat ; and write to CRTC register 00FF24 1 CA dex 00FF25 1 88 dey 00FF26 1 10 F3 bpl vdulod 00FF28 1 A6 DE ldx lineno ; retrieve X 00FF2A 1 A9 18 lda #nlines ; number of lines on screen 00FF2C 1 85 DE sta lineno ; set top line ? 00FF2E 1 A9 10 lda #>vdua ; ($10 or $04) 00FF30 1 85 E0 sta line+1 ; set MSB of screen address 00FF32 1 4C 87 FE jmp VDUCR ; set up cursor at start of line 00FF35 1 00FF35 1 ; COS Entry Point on Reset 00FF35 1 A2 19 RST: ldx #$19 ; set up 14 OS vector addresses 00FF37 1 BD 96 FF tablod: lda VECTAB,x ; copy from vectors table 00FF3A 1 9D 02 02 sta BRKVEC,x ; to RAM vector redirections 00FF3D 1 CA dex 00FF3E 1 10 F7 bpl tablod ; copy the whole table 00FF40 1 E8 inx ; X=0 00FF41 1 86 E8 stx mesage ; messages enabled 00FF43 1 86 EA stx drive ; set default drive to 0 00FF45 1 A2 40 ldx #$40 00FF47 1 8E 22 0E stx ddr_a ; set PA6 of port A as an output for CASOUT 00FF4A 1 ; (note that there is no need to set-up port B ODR 00FF4A 1 ; for the keyboard as it defaults to input) 00FF4A 1 A9 0A lda #LF 00FF4C 1 85 FE sta not_pr ; set character not to print (LF) 00FF4E 1 4D 00 F0 eor EXTROM ; test for an extension ROM 00FF51 1 CD 01 F0 cmp EXTROM+1 ; is there one there ? 00FF54 1 D0 03 bne norom ; no enter Acorn COS 00FF56 1 4C 02 F0 jmp EXTROM+2 ; enter extension ROM at $F002 00FF59 1 20 00 F8 norom: jsr OUTSTR ; enable screen and output start-up message 00FF5C 1 06 0C 41 63 .byte ACK,FF,"Acorn Cos",LF 00FF60 1 6F 72 6E 20 00FF64 1 43 6F 73 0A 00FF68 1 00FF68 1 ; COS Re-entry Point on BRK 00FF68 1 A2 FF BRK0: ldx #$FF 00FF6A 1 9A txs ; initialise stack pointer 00FF6B 1 E8 inx ; X=0 00FF6C 1 86 DD stx chkflg ; clear all file check flags 00FF6E 1 20 ED FF jsr OSCRLF ; output a CR LF and 00FF71 1 20 1D F8 syscom: jsr COMIN ; get command from buffer 00FF74 1 20 5C F9 jsr COSCLI ; execute it 00FF77 1 4C 71 FF jmp syscom ; and carry on 00FF7A 1 00FF7A 1 .if vdutyp = 80 00FF7A 1 ; 80x25 VDU Original parameters for HD46505SP-2 (newer part number is HD68B45S) CRTC (character clock is 2MHz, character time is 0.5uS) 00FF7A 1 7F VDUPAR: .byte $7F ; Horizontal Total Register (R0) the horizontal frequency, the total number of characters displayed 00FF7B 1 ; and non-displayed per line - 1: 128 (15,625kHz) 00FF7B 1 50 .byte $50 ; Horizontal Displayed Register (R1) the number of displayed characters per line: 80 00FF7C 1 66 .byte $66 ; Horizontal Sync Position Register (R2) the position (start) of the horizontal sync: x102 i.e. 51uS 00FF7D 1 62 .byte $62 ; (Horizontal) Sync Width Register (R3) bits 0-3: the width (character clocks) of the horizontal sync pulse: x2(1uS) 00FF7E 1 ; bits 4-7: the vertical sync pulse width in scan line times: x6 (384uS) 00FF7E 1 1E .byte $1E ; Vertical Total Register (R4) determines the vertical frequency (in character line times - 1): 30 i.e. 31x10x64uS 00FF7F 1 02 .byte $02 ; Vertical Total Adjust Register (R5) adjustment to vertical frequency (in scan line times): 2 i.e. 2x64uS total 19.968mS i.e. 50Hz (actually 50.08Hz) 00FF80 1 19 .byte $19 ; Vertical Displayed Register (R6) the number of displayed character rows: 25 00FF81 1 1B .byte $1B ; Vertical Sync Position Register (R7) the position of the vertical sync pulse (character row times): 27 i.e. 17.28mS 00FF82 1 40 .byte $40 ; Interlace Mode and Skew Register (R8) bits 0,1 control the raster scan mode: 0 Non-Interlace Mode 00FF83 1 ; bits 4,5 sets Display Timing skew: 0 (no delay) 00FF83 1 ; bits 6,7 sets Cursor skew: 1 (0.5uS delay) 00FF83 1 09 .byte $09 ; Maximum Scan Line Address Register (R9) the number of scan lines per character row - 1 (including spacing): 9 i.e. 10 scan lines/character 00FF84 1 68 .byte $68 ; Cursor Start Register (R10) bits 0-4 cursor start scan line: 8 00FF85 1 ; bit 5 sets the blink frequency: 1 (1/32 of vertical field rate) 00FF85 1 ; bit 6 blink enable: 1 (cursor blink enabled) 00FF85 1 09 .byte $09 ; Cursor End Register (R11) the cursor end scan line: 9 i.e. underlined cursor 00FF86 1 10 .byte $10 ; Start Address Register H (R12) address of screen RAM: $10 00FF87 1 00 .byte $00 ; Start Address Register L (R13) address of screen RAM: $00 i.e. $1000 00FF88 1 00FF88 1 EA nop ; packing 00FF89 1 EA nop 00FF8A 1 EA nop 00FF8B 1 EA nop 00FF8C 1 EA nop 00FF8D 1 EA nop 00FF8E 1 EA nop 00FF8F 1 EA nop 00FF90 1 EA nop 00FF91 1 EA nop 00FF92 1 EA nop 00FF93 1 EA nop 00FF94 1 EA nop 00FF95 1 EA nop 00FF96 1 .endif 00FF96 1 00FF96 1 .if vdutyp = 81 00FF96 1 ; 80x25 VDU Modified parameters for HD46505SP-2 (newer part number is HD68B45S) CRTC (character clock is 2MHz, character time is 0.5uS) 00FF96 1 VDUPAR: .byte $7F ; Horizontal Total Register (R0) the horizontal frequency, the total number of characters displayed 00FF96 1 ; and non-displayed per line - 1: 128 (15,625kHz) 00FF96 1 .byte $50 ; Horizontal Displayed Register (R1) the number of displayed characters per line: 80 00FF96 1 .byte $60 ; Horizontal Sync Position Register (R2) the position (start) of the horizontal sync: x96 i.e. 48uS 00FF96 1 .byte $28 ; (Horizontal) Sync Width Register (R3) bits 0-3: the width (character clocks) of the horizontal sync pulse: x8(4uS) 00FF96 1 ; bits 4-7: the vertical sync pulse width in scan line times: x2 (128uS) 00FF96 1 .byte $1E ; Vertical Total Register (R4) determines the vertical frequency (in character line times - 1): 30 i.e. 31x10x64uS 00FF96 1 .byte $02 ; Vertical Total Adjust Register (R5) adjustment to vertical frequency (in scan line times): 2 i.e. 2x64uS total 19.968mS i.e. 50Hz (actually 50.08Hz) 00FF96 1 .byte $19 ; Vertical Displayed Register (R6) the number of displayed character rows: 25 00FF96 1 .byte $1B ; Vertical Sync Position Register (R7) the position of the vertical sync pulse (character row times): 27 i.e. 17.28mS 00FF96 1 .byte $40 ; Interlace Mode and Skew Register (R8) bits 0,1 control the raster scan mode: 0 Non-Interlace Mode 00FF96 1 ; bits 4,5 sets Display Timing skew: 0 (no delay) 00FF96 1 ; bits 6,7 sets Cursor skew: 1 (0.5uS delay) 00FF96 1 .byte $09 ; Maximum Scan Line Address Register (R9) the number of scan lines per character row - 1 (including spacing): 9 i.e. 10 scan lines/character 00FF96 1 .byte $68 ; Cursor Start Register (R10) bits 0-4 cursor start scan line: 8 00FF96 1 ; bit 5 sets the blink frequency: 1 (1/32 of vertical field rate) 00FF96 1 ; bit 6 blink enable: 1 (cursor blink enabled) 00FF96 1 .byte $09 ; Cursor End Register (R11) the cursor end scan line: 9 i.e. underlined cursor 00FF96 1 .byte $10 ; Start Address Register H (R12) address of screen RAM: $10 00FF96 1 .byte $00 ; Start Address Register L (R13) address of screen RAM: $00 i.e. $1000 00FF96 1 00FF96 1 nop ; packing 00FF96 1 nop 00FF96 1 nop 00FF96 1 nop 00FF96 1 nop 00FF96 1 nop 00FF96 1 nop 00FF96 1 nop 00FF96 1 nop 00FF96 1 nop 00FF96 1 nop 00FF96 1 nop 00FF96 1 nop 00FF96 1 nop 00FF96 1 .endif 00FF96 1 00FF96 1 .if vdutyp = 40 00FF96 1 ; 40x25 (Teletext) VDU Parameters for an updated/enhanced MC6845*1 CRTC or better (character clock is 1MHz, character time is 1uS) 00FF96 1 VDUPAR: .byte $3F ; Horizontal Total Register (R0) the horizontal frequency, the total number of characters displayed 00FF96 1 ; and non-displayed per line - 1: 64 (15,625kHz) 00FF96 1 .byte $28 ; Horizontal Displayed Register (R1) the number of displayed characters per line: 40 00FF96 1 .byte $33 ; Horizontal Sync Position Register (R2) the position (start) of the horizontal sync: x51 i.e. 51uS 00FF96 1 .byte $44 ; (Horizontal) Sync Width Register (R3) bits 0-3: the width (character clocks) of the horizontal sync pulse: x4(4uS) 00FF96 1 ; bits 4-7: the vertical sync pulse width in scan line times: x4 (256uS) 00FF96 1 .byte $1E ; Vertical Total Register (R4) determines the vertical frequency (in character line times - 1): 30 i.e. 31x10x64uS 00FF96 1 .byte $02 ; Vertical Total Adjust Register (R5) adjustment to vertical frequency (in scan line times): 2 i.e. 2x64uS total 19.968mS i.e. 50Hz (actually 50.08Hz) 00FF96 1 .byte $19 ; Vertical Displayed Register (R6) the number of displayed character rows: 25 00FF96 1 .byte $1B ; Vertical Sync Position Register (R7) the position of the vertical sync pulse (character row times): 27 i.e. 17.28mS 00FF96 1 .byte $03 ; Interlace Mode Register (R8) bits 0,1 control the raster scan mode: 3 Interlace Sync and Video Mode 00FF96 1 .byte $12 ; Maximum Scan Line Address Register (R9) the number of scan lines per character row - 1 (including spacing): 18 i.e. 20 scan lines/character (10 interlaced) 00FF96 1 .byte $72 ; Cursor Start Register (R10) bits 0-4 cursor start scan line: 18 00FF96 1 ; bit 5 sets the blink frequency: 1 (1/32 of vertical field rate) 00FF96 1 ; bit 6 blink enable: 1 (cursor blink enabled) 00FF96 1 .byte $13 ; Cursor End Register (R11) the cursor end scan line: 19 i.e. underlined cursor 00FF96 1 .byte $04 ; Start Address Register H (R12) address of screen RAM: 4 00FF96 1 .byte $00 ; Start Address Register L (R13) address of screen RAM: 0 i.e. $0400 00FF96 1 00FF96 1 ; 40x25 (Teletext) VDU Parameters for an original MC6845 CRTC (character clock is 1MHz, character time is 1uS) 00FF96 1 .byte $3F ; Horizontal Total Register (R0) - the horizontal frequency, the total number of characters displayed 00FF96 1 ; and non-displayed per line - 1: 63 i.e. 64 (15,625kHz) 00FF96 1 .byte $28 ; Horizontal Displayed Register (R1) - the number of displayed characters per line: 40 00FF96 1 .byte $33 ; Horizontal Sync Position Register (R2) - the position (start) of the horizontal sync: x51 i.e. 51uS 00FF96 1 .byte $04 ; (Horizontal) Sync Width Register (R3) - the width (in character clocks) of the horizontal sync pulse: x4 (4uS) 00FF96 1 .byte $1E ; Vertical Total Register (R4) determines the vertical frequency (in character line times - 1): 30, i.e. 31x10x64uS 00FF96 1 .byte $02 ; Vertical Total Adjust Register (R5) adjustment to vertical frequency (in scan line times): 2 i.e. 2x64uS total 19.968mS i.e. 50Hz (actually 50.08Hz) 00FF96 1 .byte $19 ; Vertical Displayed Register (R6) the number of displayed character rows: 25 00FF96 1 .byte $1B ; Vertical Sync Position Register (R7) the position of the vertical sync pulse (in character row times): 27 i.e. 17.28mS 00FF96 1 .byte $00 ; Interlace Mode Register (R8) controls the raster scan mode: 0 Normal Sync (non-interlace) 00FF96 1 .byte $09 ; Maximum Scan Line Address Register (R9) the number of scan lines per character row - 1 (including spacing): 9 i.e. 10 scan lines/character 00FF96 1 .byte $68 ; Cursor Start Register (R10) bits 0-4 cursor start scan line: 8 00FF96 1 ; bit 5 sets the blink frequency: 1 (1/32 of vertical field rate) 00FF96 1 ; bit 6 blink enable: 1 (cursor blink enabled) 00FF96 1 .byte $09 ; Cursor End Register (R11) the cursor end scan line: 9 i.e. underlined cursor 00FF96 1 .byte $04 ; Start Address Register H (R12) address of screen RAM: 4 00FF96 1 .byte $00 ; Start Address Register L (R13) address of screen RAM: 0 i.e. $0400 00FF96 1 .endif 00FF96 1 00FF96 1 ; Table Of OS Call Vectors 00FF96 1 68 FF VECTAB: .byte BRK0 ; vector to BRK routine (re-enters COS) 00FF98 1 91 F9 .byte ERR ; vector to IRQ handler (displays Com? error message) 00FF9A 1 5C F9 .byte COSCLI ; vector to COS Command Line Interpreter 00FF9C 1 97 FD .byte WRC ; vector to write character 00FF9E 1 54 FD .byte RDC ; vector to read character 00FFA0 1 F0 F9 .byte CLOD ; vector to cassette load 00FFA2 1 AB FB .byte CSAV ; vector to cassette save 00FFA4 1 91 F9 .byte ERR ; vector to read arguments (displays Com? error message) 00FFA6 1 91 F9 .byte ERR ; vector to set arguments (displays Com? error message) 00FFA8 1 A6 FC .byte BGT ; vector to get byte from cassette 00FFAA 1 23 FD .byte BPT ; vector to put byte to cassette 00FFAC 1 91 F9 .byte ERR ; vector to find file (displays Com? error message) 00FFAE 1 91 F9 .byte ERR ; vector to shut file (displays Com? error message) 00FFB0 1 91 F9 .byte ERR ; vector to ECONET (displays Com? error message) 00FFB2 1 00FFB2 1 ; IRQ Handler Entry Point 00FFB2 1 85 FF IRQ: sta irqa ; save A 00FFB4 1 68 pla ; retrieve the status register 00FFB5 1 48 pha ; and put it back on the stack 00FFB6 1 29 10 and #$10 ; which interrupt was it, IRQ or BRK ? 00FFB8 1 D0 06 bne brkset 00FFBA 1 A5 FF lda irqa ; IRQ - retrieve A 00FFBC 1 48 pha ; and save on stack 00FFBD 1 6C 04 02 jmp (IRQVEC) ; jump to the IRQ vector 00FFC0 1 A5 FF brkset: lda irqa ; BRK - retrieve A 00FFC2 1 28 plp ; get a copy of the status register from the stack 00FFC3 1 08 php 00FFC4 1 6C 02 02 jmp (BRKVEC) ; and jump to the BRK vector 00FFC7 1 00FFC7 1 ; NMI Handler Entry Point 00FFC7 1 48 NMI: pha ; save accumulator on stack 00FFC8 1 6C 00 02 jmp (NMIVEC) ; jump to NMI vector (not defined by COS) 00FFCB 1 6C 1A 02 OSSHUT: jmp (SHTVEC) ; OS Call: SHUT file 00FFCE 1 6C 18 02 OSFIND: jmp (FNDVEC) ; OS Call: FIND file 00FFD1 1 6C 16 02 OSBPUT: jmp (BPTVEC) ; OS Call: PUT Byte to open file 00FFD4 1 6C 14 02 OSBGET: jmp (BGTVEC) ; OS Call: GET Byte from open file 00FFD7 1 6C 12 02 OSSTAR: jmp (STRVEC) ; OS Call: SeT ARguments 00FFDA 1 6C 10 02 OSRDAR: jmp (RDRVEC) ; OS Call: ReaD ARguments 00FFDD 1 6C 0E 02 OSSAVE: jmp (SAVVEC) ; OS Call: SAVE program 00FFE0 1 6C 0C 02 OSLOAD: jmp (LODVEC) ; OS Call: LOAD program 00FFE3 1 6C 0A 02 OSRDCH: jmp (RDCVEC) ; OS Call: ReaD byte from input CHannel 00FFE6 1 20 E3 FF OSECHO: jsr OSRDCH ; OS Call: ECHO byte from input channel to output channel 00FFE9 1 C9 0D OSASCI: cmp #CR ; OS Call: writes character to output channel, if CR outputs LF as well 00FFEB 1 D0 07 bne OSWRCH ; if not CR - output the character 00FFED 1 A9 0A OSCRLF: lda #LF ; OS Call: writes CR LF to output channel 00FFEF 1 20 F4 FF jsr OSWRCH ; if CR - output LF 00FFF2 1 A9 0D lda #CR ; and then output CR 00FFF4 1 6C 08 02 OSWRCH: jmp (WRCVEC) ; OS Call: WRite Character to output CHannel 00FFF7 1 6C 06 02 OSCCLI: jmp (COMVEC) ; OS Call: execute command in input buffer 00FFFA 1 00FFFA 1 C7 FF .byte NMI ; Processor NMI Vector 00FFFC 1 35 FF .byte RST ; Processor Reset Vector 00FFFE 1 B2 FF .byte IRQ ; Processor IRQ Vector 00FFFF 1